diff options
Diffstat (limited to 'src/plugins/platforms')
266 files changed, 6999 insertions, 4516 deletions
diff --git a/src/plugins/platforms/android/android.pro b/src/plugins/platforms/android/android.pro index bd3fe5a6cc..03592bfa7d 100644 --- a/src/plugins/platforms/android/android.pro +++ b/src/plugins/platforms/android/android.pro @@ -43,7 +43,8 @@ SOURCES += $$PWD/androidplatformplugin.cpp \ $$PWD/qandroidplatformbackingstore.cpp \ $$PWD/qandroidplatformopenglcontext.cpp \ $$PWD/qandroidplatformforeignwindow.cpp \ - $$PWD/qandroideventdispatcher.cpp + $$PWD/qandroideventdispatcher.cpp \ + $$PWD/qandroidplatformoffscreensurface.cpp HEADERS += $$PWD/qandroidplatformintegration.h \ $$PWD/androiddeadlockprotector.h \ @@ -71,7 +72,8 @@ HEADERS += $$PWD/qandroidplatformintegration.h \ $$PWD/qandroidplatformbackingstore.h \ $$PWD/qandroidplatformopenglcontext.h \ $$PWD/qandroidplatformforeignwindow.h \ - $$PWD/qandroideventdispatcher.h + $$PWD/qandroideventdispatcher.h \ + $$PWD/qandroidplatformoffscreensurface.h qtConfig(android-style-assets): SOURCES += $$PWD/extract.cpp else: SOURCES += $$PWD/extract-dummy.cpp diff --git a/src/plugins/platforms/android/androidjniinput.cpp b/src/plugins/platforms/android/androidjniinput.cpp index d3bb089aa4..8372bf6484 100644 --- a/src/plugins/platforms/android/androidjniinput.cpp +++ b/src/plugins/platforms/android/androidjniinput.cpp @@ -206,7 +206,8 @@ namespace QtAndroidInput m_touchPoints.clear(); } - static void touchAdd(JNIEnv */*env*/, jobject /*thiz*/, jint /*winId*/, jint id, jint action, jboolean /*primary*/, jint x, jint y, jfloat size, jfloat pressure) + static void touchAdd(JNIEnv */*env*/, jobject /*thiz*/, jint /*winId*/, jint id, jint action, jboolean /*primary*/, jint x, jint y, + jfloat major, jfloat minor, jfloat rotation, jfloat pressure) { Qt::TouchPointState state = Qt::TouchPointStationary; switch (action) { @@ -229,12 +230,13 @@ namespace QtAndroidInput QWindowSystemInterface::TouchPoint touchPoint; touchPoint.id = id; touchPoint.pressure = pressure; + touchPoint.rotation = rotation * 180 / M_PI; touchPoint.normalPosition = QPointF(double(x / dw), double(y / dh)); touchPoint.state = state; - touchPoint.area = QRectF(x - double(dw*size) / 2.0, - y - double(dh*size) / 2.0, - double(dw*size), - double(dh*size)); + touchPoint.area = QRectF(x - double(minor), + y - double(major), + double(minor * 2), + double(major * 2)); m_touchPoints.push_back(touchPoint); if (state == Qt::TouchPointPressed) { @@ -817,7 +819,7 @@ namespace QtAndroidInput static JNINativeMethod methods[] = { {"touchBegin","(I)V",(void*)touchBegin}, - {"touchAdd","(IIIZIIFF)V",(void*)touchAdd}, + {"touchAdd","(IIIZIIFFFF)V",(void*)touchAdd}, {"touchEnd","(II)V",(void*)touchEnd}, {"mouseDown", "(III)V", (void *)mouseDown}, {"mouseUp", "(III)V", (void *)mouseUp}, diff --git a/src/plugins/platforms/android/qandroidplatformforeignwindow.cpp b/src/plugins/platforms/android/qandroidplatformforeignwindow.cpp index 8c1f0ea8d2..1c920c0af9 100644 --- a/src/plugins/platforms/android/qandroidplatformforeignwindow.cpp +++ b/src/plugins/platforms/android/qandroidplatformforeignwindow.cpp @@ -45,12 +45,11 @@ QT_BEGIN_NAMESPACE -QAndroidPlatformForeignWindow::QAndroidPlatformForeignWindow(QWindow *window) +QAndroidPlatformForeignWindow::QAndroidPlatformForeignWindow(QWindow *window, WId nativeHandle) : QAndroidPlatformWindow(window), m_surfaceId(-1) { - const WId wId = window->property("_q_foreignWinId").value<WId>(); - m_view = reinterpret_cast<jobject>(wId); + m_view = reinterpret_cast<jobject>(nativeHandle); if (m_view.isValid()) QtAndroid::setViewVisibility(m_view.object(), false); } diff --git a/src/plugins/platforms/android/qandroidplatformforeignwindow.h b/src/plugins/platforms/android/qandroidplatformforeignwindow.h index d42c36dcee..af1eee5499 100644 --- a/src/plugins/platforms/android/qandroidplatformforeignwindow.h +++ b/src/plugins/platforms/android/qandroidplatformforeignwindow.h @@ -49,7 +49,7 @@ QT_BEGIN_NAMESPACE class QAndroidPlatformForeignWindow : public QAndroidPlatformWindow { public: - explicit QAndroidPlatformForeignWindow(QWindow *window); + explicit QAndroidPlatformForeignWindow(QWindow *window, WId nativeHandle); ~QAndroidPlatformForeignWindow(); void lower() override; void raise() override; @@ -57,6 +57,7 @@ public: void setVisible(bool visible) override; void applicationStateChanged(Qt::ApplicationState state) override; void setParent(const QPlatformWindow *window) override; + bool isForeignWindow() const override { return true; } private: int m_surfaceId; diff --git a/src/plugins/platforms/android/qandroidplatformintegration.cpp b/src/plugins/platforms/android/qandroidplatformintegration.cpp index de9e27e595..73aa9d0e8a 100644 --- a/src/plugins/platforms/android/qandroidplatformintegration.cpp +++ b/src/plugins/platforms/android/qandroidplatformintegration.cpp @@ -65,6 +65,7 @@ #include "qandroidplatformservices.h" #include "qandroidplatformtheme.h" #include "qandroidsystemlocale.h" +#include "qandroidplatformoffscreensurface.h" #include <QtPlatformHeaders/QEGLNativeContext> @@ -262,12 +263,20 @@ QPlatformOffscreenSurface *QAndroidPlatformIntegration::createPlatformOffscreenS { if (!QtAndroid::activity()) return nullptr; + QSurfaceFormat format(surface->requestedFormat()); format.setAlphaBufferSize(8); format.setRedBufferSize(8); format.setGreenBufferSize(8); format.setBlueBufferSize(8); + if (surface->nativeHandle()) { + // Adopt existing offscreen Surface + // The expectation is that nativeHandle is an ANativeWindow* representing + // an android.view.Surface + return new QAndroidPlatformOffscreenSurface(m_eglDisplay, format, surface); + } + return new QEGLPbuffer(m_eglDisplay, format, surface); } @@ -275,10 +284,13 @@ QPlatformWindow *QAndroidPlatformIntegration::createPlatformWindow(QWindow *wind { if (!QtAndroid::activity()) return nullptr; - if (window->type() == Qt::ForeignWindow) - return new QAndroidPlatformForeignWindow(window); - else - return new QAndroidPlatformOpenGLWindow(window, m_eglDisplay); + + return new QAndroidPlatformOpenGLWindow(window, m_eglDisplay); +} + +QPlatformWindow *QAndroidPlatformIntegration::createForeignWindow(QWindow *window, WId nativeHandle) const +{ + return new QAndroidPlatformForeignWindow(window, nativeHandle); } QAbstractEventDispatcher *QAndroidPlatformIntegration::createEventDispatcher() const diff --git a/src/plugins/platforms/android/qandroidplatformintegration.h b/src/plugins/platforms/android/qandroidplatformintegration.h index 2337801250..be10c3d161 100644 --- a/src/plugins/platforms/android/qandroidplatformintegration.h +++ b/src/plugins/platforms/android/qandroidplatformintegration.h @@ -78,6 +78,7 @@ public: bool hasCapability(QPlatformIntegration::Capability cap) const override; QPlatformWindow *createPlatformWindow(QWindow *window) const override; + QPlatformWindow *createForeignWindow(QWindow *window, WId nativeHandle) const override; QPlatformBackingStore *createPlatformBackingStore(QWindow *window) const override; QPlatformOpenGLContext *createPlatformOpenGLContext(QOpenGLContext *context) const override; QAbstractEventDispatcher *createEventDispatcher() const override; diff --git a/src/plugins/platforms/android/qandroidplatformoffscreensurface.cpp b/src/plugins/platforms/android/qandroidplatformoffscreensurface.cpp new file mode 100644 index 0000000000..c7d832efb6 --- /dev/null +++ b/src/plugins/platforms/android/qandroidplatformoffscreensurface.cpp @@ -0,0 +1,73 @@ +/**************************************************************************** +** +** 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 "qandroidplatformoffscreensurface.h" + +#include <QtGui/QOffscreenSurface> +#include <QtEglSupport/private/qeglconvenience_p.h> + +#include <android/native_window.h> + +QT_BEGIN_NAMESPACE + +QAndroidPlatformOffscreenSurface::QAndroidPlatformOffscreenSurface(EGLDisplay display, const QSurfaceFormat &format, QOffscreenSurface *offscreenSurface) + : QPlatformOffscreenSurface(offscreenSurface) + , m_format(format) + , m_display(display) + , m_surface(EGL_NO_SURFACE) +{ + // Get native handle + ANativeWindow *surfaceTexture = (ANativeWindow*)offscreenSurface->nativeHandle(); + + EGLConfig config = q_configFromGLFormat(m_display, m_format, false); + if (config) { + const EGLint attributes[] = { + EGL_NONE + }; + m_surface = eglCreateWindowSurface(m_display, config, surfaceTexture, attributes); + } +} + +QAndroidPlatformOffscreenSurface::~QAndroidPlatformOffscreenSurface() +{ + eglDestroySurface(m_display, m_surface); +} + +QT_END_NAMESPACE + diff --git a/src/plugins/platforms/android/qandroidplatformoffscreensurface.h b/src/plugins/platforms/android/qandroidplatformoffscreensurface.h new file mode 100644 index 0000000000..461f949254 --- /dev/null +++ b/src/plugins/platforms/android/qandroidplatformoffscreensurface.h @@ -0,0 +1,67 @@ +/**************************************************************************** +** +** 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 QANDROIDPLATFORMOFFSCREENSURFACETEXTURE_H +#define QANDROIDPLATFORMOFFSCREENSURFACETEXTURE_H + +#include <qpa/qplatformoffscreensurface.h> +#include <QtEglSupport/private/qeglplatformcontext_p.h> + +QT_BEGIN_NAMESPACE +class QOffscreenSurface; +class QAndroidPlatformOffscreenSurface : public QPlatformOffscreenSurface +{ +public: + QAndroidPlatformOffscreenSurface(EGLDisplay display, const QSurfaceFormat &format, + QOffscreenSurface *offscreenSurface); + ~QAndroidPlatformOffscreenSurface(); + + QSurfaceFormat format() const override { return m_format; } + bool isValid() const override { return m_surface != EGL_NO_SURFACE; } + + EGLSurface surface() const { return m_surface; } +private: + QSurfaceFormat m_format; + EGLDisplay m_display; + EGLSurface m_surface; +}; + +QT_END_NAMESPACE + +#endif // QANDROIDPLATFORMOFFSCREENSURFACETEXTURE_H diff --git a/src/plugins/platforms/android/qandroidplatformopenglcontext.cpp b/src/plugins/platforms/android/qandroidplatformopenglcontext.cpp index 4d52085a83..d3810329c5 100644 --- a/src/plugins/platforms/android/qandroidplatformopenglcontext.cpp +++ b/src/plugins/platforms/android/qandroidplatformopenglcontext.cpp @@ -41,11 +41,13 @@ #include "qandroidplatformopenglcontext.h" #include "qandroidplatformopenglwindow.h" #include "qandroidplatformintegration.h" +#include "qandroidplatformoffscreensurface.h" #include <QtEglSupport/private/qeglpbuffer_p.h> #include <QSurface> #include <QtGui/private/qopenglcontext_p.h> +#include <QtGui/QOffscreenSurface> QT_BEGIN_NAMESPACE @@ -106,10 +108,15 @@ bool QAndroidPlatformOpenGLContext::makeCurrent(QPlatformSurface *surface) EGLSurface QAndroidPlatformOpenGLContext::eglSurfaceForPlatformSurface(QPlatformSurface *surface) { - if (surface->surface()->surfaceClass() == QSurface::Window) + if (surface->surface()->surfaceClass() == QSurface::Window) { return static_cast<QAndroidPlatformOpenGLWindow *>(surface)->eglSurface(eglConfig()); - else - return static_cast<QEGLPbuffer *>(surface)->pbuffer(); + } else { + auto platformOffscreenSurface = static_cast<QPlatformOffscreenSurface*>(surface); + if (platformOffscreenSurface->offscreenSurface()->nativeHandle()) + return static_cast<QAndroidPlatformOffscreenSurface *>(surface)->surface(); + else + return static_cast<QEGLPbuffer *>(surface)->pbuffer(); + } } QT_END_NAMESPACE diff --git a/src/plugins/platforms/android/qandroidplatformwindow.h b/src/plugins/platforms/android/qandroidplatformwindow.h index 87e5cbaa4f..91cb1e76e6 100644 --- a/src/plugins/platforms/android/qandroidplatformwindow.h +++ b/src/plugins/platforms/android/qandroidplatformwindow.h @@ -71,7 +71,7 @@ public: void requestActivateWindow() override; void updateStatusBarVisibility(); inline bool isRaster() const { - if ((window()->flags() & Qt::ForeignWindow) == Qt::ForeignWindow) + if (isForeignWindow()) return false; return window()->surfaceType() == QSurface::RasterSurface diff --git a/src/plugins/platforms/bsdfb/main.cpp b/src/plugins/platforms/bsdfb/main.cpp index f4ab3dee39..b2cd1373a7 100644 --- a/src/plugins/platforms/bsdfb/main.cpp +++ b/src/plugins/platforms/bsdfb/main.cpp @@ -1,32 +1,38 @@ /**************************************************************************** ** -** Copyright (C) 2016 The Qt Company Ltd. +** Copyright (C) 2017 The Qt Company Ltd. ** Copyright (C) 2015-2016 Oleksandr Tymoshenko <gonzo@bluezbox.com> -** Contact: http://www.qt.io/licensing/ +** Contact: https://www.qt.io/licensing/ ** ** This file is part of the plugins of the Qt Toolkit. ** -** $QT_BEGIN_LICENSE:LGPL21$ +** $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 http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. +** 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 2.1 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** 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. ** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** 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$ ** diff --git a/src/plugins/platforms/bsdfb/qbsdfbintegration.cpp b/src/plugins/platforms/bsdfb/qbsdfbintegration.cpp index 1fa13183f8..6a7d445e69 100644 --- a/src/plugins/platforms/bsdfb/qbsdfbintegration.cpp +++ b/src/plugins/platforms/bsdfb/qbsdfbintegration.cpp @@ -1,32 +1,38 @@ /**************************************************************************** ** -** Copyright (C) 2016 The Qt Company Ltd. +** Copyright (C) 2017 The Qt Company Ltd. ** Copyright (C) 2015-2016 Oleksandr Tymoshenko <gonzo@bluezbox.com> -** Contact: http://www.qt.io/licensing/ +** Contact: https://www.qt.io/licensing/ ** ** This file is part of the plugins of the Qt Toolkit. ** -** $QT_BEGIN_LICENSE:LGPL21$ +** $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 http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. +** 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 2.1 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** 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. ** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** 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$ ** diff --git a/src/plugins/platforms/bsdfb/qbsdfbintegration.h b/src/plugins/platforms/bsdfb/qbsdfbintegration.h index 2be5ea260d..81195edf7e 100644 --- a/src/plugins/platforms/bsdfb/qbsdfbintegration.h +++ b/src/plugins/platforms/bsdfb/qbsdfbintegration.h @@ -1,31 +1,37 @@ /**************************************************************************** ** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ +** 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:LGPL21$ +** $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 http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. +** 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 2.1 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** 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. ** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** 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$ ** diff --git a/src/plugins/platforms/bsdfb/qbsdfbscreen.cpp b/src/plugins/platforms/bsdfb/qbsdfbscreen.cpp index 0ef57d37e5..067a26a7b1 100644 --- a/src/plugins/platforms/bsdfb/qbsdfbscreen.cpp +++ b/src/plugins/platforms/bsdfb/qbsdfbscreen.cpp @@ -1,32 +1,38 @@ /**************************************************************************** ** -** Copyright (C) 2016 The Qt Company Ltd. +** Copyright (C) 2017 The Qt Company Ltd. ** Copyright (C) 2015-2016 Oleksandr Tymoshenko <gonzo@bluezbox.com> -** Contact: http://www.qt.io/licensing/ +** Contact: https://www.qt.io/licensing/ ** ** This file is part of the plugins of the Qt Toolkit. ** -** $QT_BEGIN_LICENSE:LGPL21$ +** $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 http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. +** 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 2.1 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** 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. ** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** 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$ ** @@ -243,7 +249,7 @@ QRegion QBsdFbScreen::doRedraw() const auto rects = touched.rects(); for (const QRect &rect : rects) - m_blitter->drawImage(rect, *mScreenImage, rect); + m_blitter->drawImage(rect, mScreenImage, rect); return touched; } diff --git a/src/plugins/platforms/bsdfb/qbsdfbscreen.h b/src/plugins/platforms/bsdfb/qbsdfbscreen.h index 3e244e3460..890a2eb757 100644 --- a/src/plugins/platforms/bsdfb/qbsdfbscreen.h +++ b/src/plugins/platforms/bsdfb/qbsdfbscreen.h @@ -1,32 +1,38 @@ /**************************************************************************** ** -** Copyright (C) 2016 The Qt Company Ltd. +** Copyright (C) 2017 The Qt Company Ltd. ** Copyright (C) 2015-2016 Oleksandr Tymoshenko <gonzo@bluezbox.com> -** Contact: http://www.qt.io/licensing/ +** Contact: https://www.qt.io/licensing/ ** ** This file is part of the plugins of the Qt Toolkit. ** -** $QT_BEGIN_LICENSE:LGPL21$ +** $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 http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. +** 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 2.1 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** 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. ** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** 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$ ** diff --git a/src/plugins/platforms/cocoa/cocoa.pro b/src/plugins/platforms/cocoa/cocoa.pro index 0664841c2d..62935210be 100644 --- a/src/plugins/platforms/cocoa/cocoa.pro +++ b/src/plugins/platforms/cocoa/cocoa.pro @@ -86,6 +86,8 @@ QT += \ accessibility_support-private clipboard_support-private theme_support-private \ fontdatabase_support-private graphics_support-private cgl_support-private +CONFIG += no_app_extension_api_only + qtHaveModule(widgets) { OBJECTIVE_SOURCES += \ qpaintengine_mac.mm \ diff --git a/src/plugins/platforms/cocoa/images/copyarrowcursor.png b/src/plugins/platforms/cocoa/images/copyarrowcursor.png Binary files differdeleted file mode 100644 index 13dfca95bc..0000000000 --- a/src/plugins/platforms/cocoa/images/copyarrowcursor.png +++ /dev/null diff --git a/src/plugins/platforms/cocoa/images/forbiddencursor.png b/src/plugins/platforms/cocoa/images/forbiddencursor.png Binary files differdeleted file mode 100644 index a9f21b4a5e..0000000000 --- a/src/plugins/platforms/cocoa/images/forbiddencursor.png +++ /dev/null diff --git a/src/plugins/platforms/cocoa/images/leopard-unified-toolbar-on.png b/src/plugins/platforms/cocoa/images/leopard-unified-toolbar-on.png Binary files differdeleted file mode 100644 index 6716597046..0000000000 --- a/src/plugins/platforms/cocoa/images/leopard-unified-toolbar-on.png +++ /dev/null diff --git a/src/plugins/platforms/cocoa/qcocoaapplication.mm b/src/plugins/platforms/cocoa/qcocoaapplication.mm index c5ae4bc2bf..3b950efa55 100644 --- a/src/plugins/platforms/cocoa/qcocoaapplication.mm +++ b/src/plugins/platforms/cocoa/qcocoaapplication.mm @@ -76,6 +76,7 @@ #include "qcocoaintrospection.h" #include "qcocoaapplicationdelegate.h" #include "qcocoahelpers.h" +#include "qcocoawindow.h" #include <qguiapplication.h> #include <qdebug.h> @@ -148,6 +149,21 @@ static const QByteArray q_macLocalEventType = QByteArrayLiteral("mac_generic_NSE @end +static void qt_maybeSendKeyEquivalentUpEvent(NSEvent *event) +{ + // Cocoa is known for not sending key up events for key + // equivalents, regardless of whether it's an actual + // recognized key equivalent. We decide to force fate + // and forward the key event to the key (focus) window. + // However, non-Qt windows will not (and should not) get + // any special treatment, only QWindow-owned NSWindows. + if (event.type == NSKeyUp && (event.modifierFlags & NSCommandKeyMask)) { + NSWindow *targetWindow = event.window; + if ([targetWindow.class conformsToProtocol:@protocol(QNSWindowProtocol)]) + [targetWindow sendEvent:event]; + } +} + @implementation QT_MANGLE_NAMESPACE(QNSApplication) - (void)QT_MANGLE_NAMESPACE(qt_sendEvent_original):(NSEvent *)event @@ -164,16 +180,20 @@ static const QByteArray q_macLocalEventType = QByteArrayLiteral("mac_generic_NSE // be called instead of sendEvent if redirection occurs. // 'self' will then be an instance of NSApplication // (and not QNSApplication) - if (![NSApp QT_MANGLE_NAMESPACE(qt_filterEvent):event]) + if (![NSApp QT_MANGLE_NAMESPACE(qt_filterEvent):event]) { [self QT_MANGLE_NAMESPACE(qt_sendEvent_original):event]; + qt_maybeSendKeyEquivalentUpEvent(event); + } } - (void)sendEvent:(NSEvent *)event { // This method will be called if // no redirection occurs - if (![NSApp QT_MANGLE_NAMESPACE(qt_filterEvent):event]) + if (![NSApp QT_MANGLE_NAMESPACE(qt_filterEvent):event]) { [super sendEvent:event]; + qt_maybeSendKeyEquivalentUpEvent(event); + } } @end diff --git a/src/plugins/platforms/cocoa/qcocoabackingstore.mm b/src/plugins/platforms/cocoa/qcocoabackingstore.mm index a74995319b..1d7ad772dc 100644 --- a/src/plugins/platforms/cocoa/qcocoabackingstore.mm +++ b/src/plugins/platforms/cocoa/qcocoabackingstore.mm @@ -57,7 +57,8 @@ QCocoaBackingStore::~QCocoaBackingStore() QImage::Format QCocoaBackingStore::format() const { - if (static_cast<QCocoaWindow *>(window()->handle())->m_drawContentBorderGradient) + QCocoaWindow *cocoaWindow = static_cast<QCocoaWindow *>(window()->handle()); + if (cocoaWindow && cocoaWindow->m_drawContentBorderGradient) return QImage::Format_ARGB32_Premultiplied; return QRasterBackingStore::format(); diff --git a/src/plugins/platforms/cocoa/qcocoacolordialoghelper.mm b/src/plugins/platforms/cocoa/qcocoacolordialoghelper.mm index e53c085e41..a8974c4de5 100644 --- a/src/plugins/platforms/cocoa/qcocoacolordialoghelper.mm +++ b/src/plugins/platforms/cocoa/qcocoacolordialoghelper.mm @@ -80,7 +80,7 @@ QT_NAMESPACE_ALIAS_OBJC_CLASS(QNSColorPanelDelegate); mHelper = 0; mStolenContentView = 0; mPanelButtons = nil; - mResultCode = NSCancelButton; + mResultCode = NSModalResponseCancel; mDialogIsExecuting = false; mResultSet = false; mClosingDueToKnownButton = false; @@ -168,7 +168,7 @@ QT_NAMESPACE_ALIAS_OBJC_CLASS(QNSColorPanelDelegate); mClosingDueToKnownButton = true; [mColorPanel close]; [self updateQtColor]; - [self finishOffWithCode:NSOKButton]; + [self finishOffWithCode:NSModalResponseOK]; } - (void)onCancelClicked @@ -177,7 +177,7 @@ QT_NAMESPACE_ALIAS_OBJC_CLASS(QNSColorPanelDelegate); mClosingDueToKnownButton = true; [mColorPanel close]; mQtColor = QColor(); - [self finishOffWithCode:NSCancelButton]; + [self finishOffWithCode:NSModalResponseCancel]; } } @@ -238,12 +238,12 @@ QT_NAMESPACE_ALIAS_OBJC_CLASS(QNSColorPanelDelegate); [NSApp runModalForWindow:mColorPanel]; mDialogIsExecuting = false; - return (mResultCode == NSOKButton); + return (mResultCode == NSModalResponseOK); } - (QPlatformDialogHelper::DialogCode)dialogResultCode { - return (mResultCode == NSOKButton) ? QPlatformDialogHelper::Accepted : QPlatformDialogHelper::Rejected; + return (mResultCode == NSModalResponseOK) ? QPlatformDialogHelper::Accepted : QPlatformDialogHelper::Rejected; } - (BOOL)windowShouldClose:(id)window @@ -252,7 +252,7 @@ QT_NAMESPACE_ALIAS_OBJC_CLASS(QNSColorPanelDelegate); if (!mPanelButtons) [self updateQtColor]; if (mDialogIsExecuting) { - [self finishOffWithCode:NSCancelButton]; + [self finishOffWithCode:NSModalResponseCancel]; } else { mResultSet = true; if (mHelper) @@ -278,7 +278,7 @@ QT_NAMESPACE_ALIAS_OBJC_CLASS(QNSColorPanelDelegate); // This check will prevent any such recursion. if (!mResultSet) { mResultSet = true; - if (mResultCode == NSCancelButton) { + if (mResultCode == NSModalResponseCancel) { emit mHelper->reject(); } else { emit mHelper->accept(); diff --git a/src/plugins/platforms/cocoa/qcocoacursor.mm b/src/plugins/platforms/cocoa/qcocoacursor.mm index 3df2a7c962..99a136d384 100644 --- a/src/plugins/platforms/cocoa/qcocoacursor.mm +++ b/src/plugins/platforms/cocoa/qcocoacursor.mm @@ -97,6 +97,9 @@ NSCursor *QCocoaCursor::convertCursor(QCursor *cursor) case Qt::ArrowCursor: cocoaCursor= [NSCursor arrowCursor]; break; + case Qt::ForbiddenCursor: + cocoaCursor = [NSCursor operationNotAllowedCursor]; + break; case Qt::CrossCursor: cocoaCursor = [NSCursor crosshairCursor]; break; @@ -123,7 +126,7 @@ NSCursor *QCocoaCursor::convertCursor(QCursor *cursor) cocoaCursor = [NSCursor crosshairCursor]; break; case Qt::DragCopyCursor: - cocoaCursor = [NSCursor crosshairCursor]; + cocoaCursor = [NSCursor dragCopyCursor]; break; case Qt::DragLinkCursor: cocoaCursor = [NSCursor dragLinkCursor]; @@ -235,10 +238,6 @@ NSCursor *QCocoaCursor::createCursorData(QCursor *cursor) QPixmap pixmap = QPixmap(QLatin1String(":/qt-project.org/mac/cursors/images/waitcursor.png")); return createCursorFromPixmap(pixmap, hotspot); break; } - case Qt::ForbiddenCursor: { - QPixmap pixmap = QPixmap(QLatin1String(":/qt-project.org/mac/cursors/images/forbiddencursor.png")); - return createCursorFromPixmap(pixmap, hotspot); - break; } #define QT_USE_APPROXIMATE_CURSORS #ifdef QT_USE_APPROXIMATE_CURSORS case Qt::SizeVerCursor: diff --git a/src/plugins/platforms/cocoa/qcocoadrag.mm b/src/plugins/platforms/cocoa/qcocoadrag.mm index a0967750e7..c71e80d191 100644 --- a/src/plugins/platforms/cocoa/qcocoadrag.mm +++ b/src/plugins/platforms/cocoa/qcocoadrag.mm @@ -132,7 +132,7 @@ Qt::DropAction QCocoaDrag::drag(QDrag *o) QPixmap pm = dragPixmap(m_drag, hotSpot); QSize pmDeviceIndependentSize = pm.size() / pm.devicePixelRatio(); NSImage *nsimage = qt_mac_create_nsimage(pm); - [nsimage setSize:pmDeviceIndependentSize.toCGSize()]; + [nsimage setSize:NSSizeFromCGSize(pmDeviceIndependentSize.toCGSize())]; QMacPasteboard dragBoard((CFStringRef) NSDragPboard, QMacInternalPasteboardMime::MIME_DND); m_drag->mimeData()->setData(QLatin1String("application/x-qt-mime-type-name"), QByteArray("dummy")); diff --git a/src/plugins/platforms/cocoa/qcocoaeventdispatcher.mm b/src/plugins/platforms/cocoa/qcocoaeventdispatcher.mm index 72c7856c2d..d2f985ec87 100644 --- a/src/plugins/platforms/cocoa/qcocoaeventdispatcher.mm +++ b/src/plugins/platforms/cocoa/qcocoaeventdispatcher.mm @@ -401,7 +401,7 @@ bool QCocoaEventDispatcher::processEvents(QEventLoop::ProcessEventsFlags flags) // [NSApp run], which is the normal code path for cocoa applications. if (NSModalSession session = d->currentModalSession()) { QBoolBlocker execGuard(d->currentExecIsNSAppRun, false); - while ([NSApp runModalSession:session] == NSRunContinuesResponse && !d->interrupt) + while ([NSApp runModalSession:session] == NSModalResponseContinue && !d->interrupt) qt_mac_waitForMoreEvents(NSModalPanelRunLoopMode); if (!d->interrupt && session == d->currentModalSessionCached) { @@ -435,7 +435,7 @@ bool QCocoaEventDispatcher::processEvents(QEventLoop::ProcessEventsFlags flags) if (flags & QEventLoop::WaitForMoreEvents) qt_mac_waitForMoreEvents(NSModalPanelRunLoopMode); NSInteger status = [NSApp runModalSession:session]; - if (status != NSRunContinuesResponse && session == d->currentModalSessionCached) { + if (status != NSModalResponseContinue && session == d->currentModalSessionCached) { // INVARIANT: Someone called [NSApp stopModal:] from outside the event // dispatcher (e.g to stop a native dialog). But that call wrongly stopped // 'session' as well. As a result, we need to restart all internal sessions: diff --git a/src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm b/src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm index 2aaad38659..e39d5e4546 100644 --- a/src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm +++ b/src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm @@ -63,6 +63,7 @@ #include <stdlib.h> #include <qabstracteventdispatcher.h> #include <qsysinfo.h> +#include <qoperatingsystemversion.h> #include <qglobal.h> #include <QDir> @@ -164,7 +165,7 @@ QT_NAMESPACE_ALIAS_OBJC_CLASS(QNSOpenSavePanelDelegate); [mSavePanel setDelegate:self]; #if QT_OSX_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_10_11) - if (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_11) + if (QOperatingSystemVersion::current() >= QOperatingSystemVersion::OSXElCapitan) mOpenPanel.accessoryViewDisclosed = YES; #endif diff --git a/src/plugins/platforms/cocoa/qcocoafontdialoghelper.mm b/src/plugins/platforms/cocoa/qcocoafontdialoghelper.mm index 33dd4260a5..e4b796dcde 100644 --- a/src/plugins/platforms/cocoa/qcocoafontdialoghelper.mm +++ b/src/plugins/platforms/cocoa/qcocoafontdialoghelper.mm @@ -106,7 +106,7 @@ QT_NAMESPACE_ALIAS_OBJC_CLASS(QNSFontPanelDelegate); mHelper = 0; mStolenContentView = 0; mPanelButtons = 0; - mResultCode = NSCancelButton; + mResultCode = NSModalResponseCancel; mDialogIsExecuting = false; mResultSet = false; @@ -171,7 +171,7 @@ QT_NAMESPACE_ALIAS_OBJC_CLASS(QNSFontPanelDelegate); - (void)onOkClicked { [mFontPanel close]; - [self finishOffWithCode:NSOKButton]; + [self finishOffWithCode:NSModalResponseOK]; } - (void)onCancelClicked @@ -179,7 +179,7 @@ QT_NAMESPACE_ALIAS_OBJC_CLASS(QNSFontPanelDelegate); if (mPanelButtons) { [mFontPanel close]; mQtFont = QFont(); - [self finishOffWithCode:NSCancelButton]; + [self finishOffWithCode:NSModalResponseCancel]; } } @@ -224,12 +224,12 @@ QT_NAMESPACE_ALIAS_OBJC_CLASS(QNSFontPanelDelegate); [NSApp runModalForWindow:mFontPanel]; mDialogIsExecuting = false; - return (mResultCode == NSOKButton); + return (mResultCode == NSModalResponseOK); } - (QPlatformDialogHelper::DialogCode)dialogResultCode { - return (mResultCode == NSOKButton) ? QPlatformDialogHelper::Accepted : QPlatformDialogHelper::Rejected; + return (mResultCode == NSModalResponseOK) ? QPlatformDialogHelper::Accepted : QPlatformDialogHelper::Rejected; } - (BOOL)windowShouldClose:(id)window @@ -238,7 +238,7 @@ QT_NAMESPACE_ALIAS_OBJC_CLASS(QNSFontPanelDelegate); if (!mPanelButtons) [self updateQtFont]; if (mDialogIsExecuting) { - [self finishOffWithCode:NSCancelButton]; + [self finishOffWithCode:NSModalResponseCancel]; } else { mResultSet = true; if (mHelper) @@ -264,7 +264,7 @@ QT_NAMESPACE_ALIAS_OBJC_CLASS(QNSFontPanelDelegate); // This check will prevent any such recursion. if (!mResultSet) { mResultSet = true; - if (mResultCode == NSCancelButton) { + if (mResultCode == NSModalResponseCancel) { emit mHelper->reject(); } else { emit mHelper->accept(); diff --git a/src/plugins/platforms/cocoa/qcocoaglcontext.mm b/src/plugins/platforms/cocoa/qcocoaglcontext.mm index a7cc19b3bf..9e688f4d1b 100644 --- a/src/plugins/platforms/cocoa/qcocoaglcontext.mm +++ b/src/plugins/platforms/cocoa/qcocoaglcontext.mm @@ -255,7 +255,8 @@ void QCocoaGLContext::setActiveWindow(QWindow *window) QCocoaWindow *cocoaWindow = static_cast<QCocoaWindow *>(window->handle()); cocoaWindow->setCurrentContext(this); - [(QNSView *) cocoaWindow->view() setQCocoaGLContext:this]; + Q_ASSERT(!cocoaWindow->isForeignWindow()); + [qnsview_cast(cocoaWindow->view()) setQCocoaGLContext:this]; } void QCocoaGLContext::updateSurfaceFormat() diff --git a/src/plugins/platforms/cocoa/qcocoahelpers.mm b/src/plugins/platforms/cocoa/qcocoahelpers.mm index 3ab6b641fa..232e40769b 100644 --- a/src/plugins/platforms/cocoa/qcocoahelpers.mm +++ b/src/plugins/platforms/cocoa/qcocoahelpers.mm @@ -151,7 +151,8 @@ Qt::DropActions qt_mac_mapNSDragOperations(NSDragOperation nsActions) a no-op. For extra verbosity and clearer code, please consider checking - that window()->type() != Qt::ForeignWindow before using this cast. + that the platform window is not a foreign window before using + this cast, via QPlatformWindow::isForeignWindow(). Do not use this method soley to check for foreign windows, as that will make the code harder to read for people not working @@ -160,10 +161,8 @@ Qt::DropActions qt_mac_mapNSDragOperations(NSDragOperation nsActions) */ QNSView *qnsview_cast(NSView *view) { - if (![view isKindOfClass:[QNSView class]]) { - qCWarning(lcQpaCocoaWindow) << "NSView is not QNSView, consider checking for Qt::ForeignWindow"; + if (![view isKindOfClass:[QNSView class]]) return nil; - } return static_cast<QNSView *>(view); } @@ -235,13 +234,13 @@ QString qt_mac_applicationName() return appName; } -int qt_mac_mainScreenHeight() +int qt_mac_primaryScreenHeight() { QMacAutoReleasePool pool; NSArray *screens = [NSScreen screens]; if ([screens count] > 0) { - // The first screen in the screens array is documented - // to have the (0,0) origin. + // The first screen in the screens array is documented to + // have the (0,0) origin and is designated the primary screen. NSRect screenFrame = [[screens objectAtIndex: 0] frame]; return screenFrame.size.height; } @@ -250,12 +249,12 @@ int qt_mac_mainScreenHeight() int qt_mac_flipYCoordinate(int y) { - return qt_mac_mainScreenHeight() - y; + return qt_mac_primaryScreenHeight() - y; } qreal qt_mac_flipYCoordinate(qreal y) { - return qt_mac_mainScreenHeight() - y; + return qt_mac_primaryScreenHeight() - y; } QPointF qt_mac_flipPoint(const NSPoint &p) diff --git a/src/plugins/platforms/cocoa/qcocoaintegration.h b/src/plugins/platforms/cocoa/qcocoaintegration.h index 32f6fe0af1..ecdd20c4dc 100644 --- a/src/plugins/platforms/cocoa/qcocoaintegration.h +++ b/src/plugins/platforms/cocoa/qcocoaintegration.h @@ -84,9 +84,18 @@ public: // ---------------------------------------------------- // Additional methods void setVirtualSiblings(const QList<QPlatformScreen *> &siblings) { m_siblings = siblings; } - NSScreen *osScreen() const; + NSScreen *nativeScreen() const; void updateGeometry(); + QPointF mapToNative(const QPointF &pos) const { return flipCoordinate(pos); } + QRectF mapToNative(const QRectF &rect) const { return flipCoordinate(rect); } + QPointF mapFromNative(const QPointF &pos) const { return flipCoordinate(pos); } + QRectF mapFromNative(const QRectF &rect) const { return flipCoordinate(rect); } + +private: + QPointF flipCoordinate(const QPointF &pos) const; + QRectF flipCoordinate(const QRectF &rect) const; + public: int m_screenIndex; QRect m_geometry; @@ -117,6 +126,7 @@ public: bool hasCapability(QPlatformIntegration::Capability cap) const Q_DECL_OVERRIDE; QPlatformWindow *createPlatformWindow(QWindow *window) const Q_DECL_OVERRIDE; + QPlatformWindow *createForeignWindow(QWindow *window, WId nativeHandle) const Q_DECL_OVERRIDE; #ifndef QT_NO_OPENGL QPlatformOpenGLContext *createPlatformOpenGLContext(QOpenGLContext *context) const Q_DECL_OVERRIDE; #endif @@ -144,7 +154,7 @@ public: QList<int> possibleKeys(const QKeyEvent *event) const Q_DECL_OVERRIDE; void updateScreens(); - QCocoaScreen *screenAtIndex(int index); + QCocoaScreen *screenForNSScreen(NSScreen *nsScreen); void setToolbar(QWindow *window, NSToolbar *toolbar); NSToolbar *toolbar(QWindow *window) const; diff --git a/src/plugins/platforms/cocoa/qcocoaintegration.mm b/src/plugins/platforms/cocoa/qcocoaintegration.mm index fe4933ed6f..9dfcb82151 100644 --- a/src/plugins/platforms/cocoa/qcocoaintegration.mm +++ b/src/plugins/platforms/cocoa/qcocoaintegration.mm @@ -69,8 +69,8 @@ static void initResources() QT_BEGIN_NAMESPACE -QCocoaScreen::QCocoaScreen(int screenIndex) : - QPlatformScreen(), m_screenIndex(screenIndex), m_refreshRate(60.0) +QCocoaScreen::QCocoaScreen(int screenIndex) + : QPlatformScreen(), m_screenIndex(screenIndex), m_refreshRate(60.0) { updateGeometry(); m_cursor = new QCocoaCursor; @@ -81,41 +81,65 @@ QCocoaScreen::~QCocoaScreen() delete m_cursor; } -NSScreen *QCocoaScreen::osScreen() const +NSScreen *QCocoaScreen::nativeScreen() const { NSArray *screens = [NSScreen screens]; - return ((NSUInteger)m_screenIndex < [screens count]) ? [screens objectAtIndex:m_screenIndex] : nil; + + // Stale reference, screen configuration has changed + if (m_screenIndex < 0 || (NSUInteger)m_screenIndex >= [screens count]) + return nil; + + return [screens objectAtIndex:m_screenIndex]; +} + +/*! + Flips the Y coordinate of the point between quadrant I and IV. + + The native coordinate system on macOS uses quadrant I, with origin + in bottom left, and Qt uses quadrant IV, with origin in top left. + + By flippig the Y coordinate, we can map the position between the + two coordinate systems. +*/ +QPointF QCocoaScreen::flipCoordinate(const QPointF &pos) const +{ + return QPointF(pos.x(), m_geometry.height() - pos.y()); +} + +/*! + Flips the Y coordinate of the rectangle between quadrant I and IV. + + The native coordinate system on macOS uses quadrant I, with origin + in bottom left, and Qt uses quadrant IV, with origin in top left. + + By flippig the Y coordinate, we can map the rectangle between the + two coordinate systems. +*/ +QRectF QCocoaScreen::flipCoordinate(const QRectF &rect) const +{ + return QRectF(flipCoordinate(rect.topLeft() + QPoint(0, rect.height())), rect.size()); } void QCocoaScreen::updateGeometry() { - NSScreen *nsScreen = osScreen(); + NSScreen *nsScreen = nativeScreen(); if (!nsScreen) return; - NSRect frameRect = [nsScreen frame]; + // At this point the geometry is in native coordinates, but the size + // is correct, which we take advantage of next when we map the native + // coordinates to the Qt coordinate system. + m_geometry = QRectF::fromCGRect(NSRectToCGRect(nsScreen.frame)).toRect(); + m_availableGeometry = QRectF::fromCGRect(NSRectToCGRect(nsScreen.visibleFrame)).toRect(); - if (m_screenIndex == 0) { - m_geometry = QRect(frameRect.origin.x, frameRect.origin.y, frameRect.size.width, frameRect.size.height); - // This is the primary screen, the one that contains the menubar. Its origin should be - // (0, 0), and it's the only one whose available geometry differs from its full geometry. - NSRect visibleRect = [nsScreen visibleFrame]; - m_availableGeometry = QRect(visibleRect.origin.x, - frameRect.size.height - (visibleRect.origin.y + visibleRect.size.height), // invert y - visibleRect.size.width, visibleRect.size.height); - } else { - // NSScreen origin is at the bottom-left corner, QScreen is at the top-left corner. - // When we get the NSScreen frame rect, we need to re-align its origin y coordinate - // w.r.t. the primary screen, whose origin is (0, 0). - NSRect r = [[[NSScreen screens] objectAtIndex:0] frame]; - QRect referenceScreenGeometry = QRect(r.origin.x, r.origin.y, r.size.width, r.size.height); - m_geometry = QRect(frameRect.origin.x, - referenceScreenGeometry.height() - (frameRect.origin.y + frameRect.size.height), - frameRect.size.width, frameRect.size.height); - - // Not primary screen. See above. - m_availableGeometry = m_geometry; - } + // The reference screen for the geometry is always the primary screen, but since + // we may be in the process of creating and registering the primary screen, we + // must special-case that and assign it direcly. + QCocoaScreen *primaryScreen = (nsScreen == [[NSScreen screens] firstObject]) ? + this : static_cast<QCocoaScreen*>(QGuiApplication::primaryScreen()->handle()); + + m_geometry = primaryScreen->mapFromNative(m_geometry).toRect(); + m_availableGeometry = primaryScreen->mapFromNative(m_availableGeometry).toRect(); m_format = QImage::Format_RGB32; m_depth = NSBitsPerPixelFromDepth([nsScreen depth]); @@ -147,8 +171,8 @@ void QCocoaScreen::updateGeometry() qreal QCocoaScreen::devicePixelRatio() const { QMacAutoReleasePool pool; - NSScreen * screen = osScreen(); - return qreal(screen ? [screen backingScaleFactor] : 1.0); + NSScreen *nsScreen = nativeScreen(); + return qreal(nsScreen ? [nsScreen backingScaleFactor] : 1.0); } QPlatformScreen::SubpixelAntialiasingType QCocoaScreen::subpixelAntialiasingTypeHint() const @@ -427,7 +451,7 @@ void QCocoaIntegration::updateScreens() // NSScreen documentation says do not cache the array returned from [NSScreen screens]. // However in practice, we can identify a screen by its pointer: if resolution changes, // the NSScreen object will be the same instance, just with different values. - if (existingScr->osScreen() == scr) { + if (existingScr->nativeScreen() == scr) { screen = existingScr; break; } @@ -451,20 +475,27 @@ void QCocoaIntegration::updateScreens() // Now the leftovers in remainingScreens are no longer current, so we can delete them. foreach (QCocoaScreen* screen, remainingScreens) { mScreens.removeOne(screen); + // Prevent stale references to NSScreen during destroy + screen->m_screenIndex = -1; destroyScreen(screen); } } -QCocoaScreen *QCocoaIntegration::screenAtIndex(int index) +QCocoaScreen *QCocoaIntegration::screenForNSScreen(NSScreen *nsScreen) { - if (index >= mScreens.count()) + NSUInteger index = [[NSScreen screens] indexOfObject:nsScreen]; + if (index == NSNotFound) + return 0; + + if (index >= unsigned(mScreens.count())) updateScreens(); - // It is possible that the screen got removed while updateScreens was called - // so we do a sanity check to be certain - if (index >= mScreens.count()) - return 0; - return mScreens.at(index); + for (QCocoaScreen *screen : mScreens) { + if (screen->nativeScreen() == nsScreen) + return screen; + } + + return 0; } bool QCocoaIntegration::hasCapability(QPlatformIntegration::Capability cap) const @@ -493,6 +524,11 @@ QPlatformWindow *QCocoaIntegration::createPlatformWindow(QWindow *window) const return new QCocoaWindow(window); } +QPlatformWindow *QCocoaIntegration::createForeignWindow(QWindow *window, WId nativeHandle) const +{ + return new QCocoaWindow(window, nativeHandle); +} + #ifndef QT_NO_OPENGL QPlatformOpenGLContext *QCocoaIntegration::createPlatformOpenGLContext(QOpenGLContext *context) const { diff --git a/src/plugins/platforms/cocoa/qcocoamenu.mm b/src/plugins/platforms/cocoa/qcocoamenu.mm index e177a24e73..8e47974d12 100644 --- a/src/plugins/platforms/cocoa/qcocoamenu.mm +++ b/src/plugins/platforms/cocoa/qcocoamenu.mm @@ -581,8 +581,8 @@ void QCocoaMenu::showPopup(const QWindow *parentWindow, const QRect &targetRect, // The calls above block, and also swallow any mouse release event, // so we need to clear any mouse button that triggered the menu popup. - if ([view isKindOfClass:[QNSView class]]) - [(QNSView *)view resetMouseButtons]; + if (!cocoaWindow->isForeignWindow()) + [qnsview_cast(view) resetMouseButtons]; } void QCocoaMenu::dismiss() diff --git a/src/plugins/platforms/cocoa/qcocoanativeinterface.mm b/src/plugins/platforms/cocoa/qcocoanativeinterface.mm index 972230349b..26ab07ffaf 100644 --- a/src/plugins/platforms/cocoa/qcocoanativeinterface.mm +++ b/src/plugins/platforms/cocoa/qcocoanativeinterface.mm @@ -172,11 +172,12 @@ void *QCocoaNativeInterface::NSPrintInfoForPrintEngine(QPrintEngine *printEngine QPixmap QCocoaNativeInterface::defaultBackgroundPixmapForQWizard() { - QCFType<CFURLRef> url; const int ExpectedImageWidth = 242; const int ExpectedImageHeight = 414; - if (LSFindApplicationForInfo(kLSUnknownCreator, CFSTR("com.apple.KeyboardSetupAssistant"), - 0, 0, &url) == noErr) { + QCFType<CFArrayRef> urls = LSCopyApplicationURLsForBundleIdentifier( + CFSTR("com.apple.KeyboardSetupAssistant"), nullptr); + if (urls && CFArrayGetCount(urls) > 0) { + CFURLRef url = (CFURLRef)CFArrayGetValueAtIndex(urls, 0); QCFType<CFBundleRef> bundle = CFBundleCreate(kCFAllocatorDefault, url); if (bundle) { url = CFBundleCopyResourceURL(bundle, CFSTR("Background"), CFSTR("png"), 0); diff --git a/src/plugins/platforms/cocoa/qcocoaresources.qrc b/src/plugins/platforms/cocoa/qcocoaresources.qrc index 4255bfba9d..1c4b941b9b 100644 --- a/src/plugins/platforms/cocoa/qcocoaresources.qrc +++ b/src/plugins/platforms/cocoa/qcocoaresources.qrc @@ -1,12 +1,7 @@ -<!DOCTYPE RCC><RCC version="1.0"> -<qresource prefix="/qt-project.org/mac/cursors"> -<file>images/copyarrowcursor.png</file> -<file>images/forbiddencursor.png</file> -<file>images/spincursor.png</file> -<file>images/waitcursor.png</file> -<file>images/sizeallcursor.png</file> -</qresource> -<qresource prefix="/qt-project.org/mac/style"> -<file>images/leopard-unified-toolbar-on.png</file> -</qresource> +<RCC> + <qresource prefix="/qt-project.org/mac/cursors"> + <file>images/spincursor.png</file> + <file>images/waitcursor.png</file> + <file>images/sizeallcursor.png</file> + </qresource> </RCC> diff --git a/src/plugins/platforms/cocoa/qcocoatheme.h b/src/plugins/platforms/cocoa/qcocoatheme.h index d47e620fbb..27c071a8cd 100644 --- a/src/plugins/platforms/cocoa/qcocoatheme.h +++ b/src/plugins/platforms/cocoa/qcocoatheme.h @@ -74,6 +74,7 @@ public: QVariant themeHint(ThemeHint hint) const Q_DECL_OVERRIDE; QString standardButtonText(int button) const Q_DECL_OVERRIDE; + QKeySequence standardButtonShortcut(int button) const Q_DECL_OVERRIDE; static const char *name; diff --git a/src/plugins/platforms/cocoa/qcocoatheme.mm b/src/plugins/platforms/cocoa/qcocoatheme.mm index 4d74c11581..d2345f9abc 100644 --- a/src/plugins/platforms/cocoa/qcocoatheme.mm +++ b/src/plugins/platforms/cocoa/qcocoatheme.mm @@ -344,6 +344,12 @@ QString QCocoaTheme::standardButtonText(int button) const return button == QPlatformDialogHelper::Discard ? msgDialogButtonDiscard() : QPlatformTheme::standardButtonText(button); } +QKeySequence QCocoaTheme::standardButtonShortcut(int button) const +{ + return button == QPlatformDialogHelper::Discard ? QKeySequence(Qt::CTRL | Qt::Key_Delete) + : QPlatformTheme::standardButtonShortcut(button); +} + QPlatformMenuItem *QCocoaTheme::createPlatformMenuItem() const { return new QCocoaMenuItem(); diff --git a/src/plugins/platforms/cocoa/qcocoawindow.h b/src/plugins/platforms/cocoa/qcocoawindow.h index 16639fd8b1..567eb7438b 100644 --- a/src/plugins/platforms/cocoa/qcocoawindow.h +++ b/src/plugins/platforms/cocoa/qcocoawindow.h @@ -96,6 +96,7 @@ QT_NAMESPACE_ALIAS_OBJC_CLASS(QNSWindowHelper); @property (nonatomic, readonly) QNSWindowHelper *helper; - (id)initWithContentRect:(NSRect)contentRect + screen:(NSScreen*)screen styleMask:(NSUInteger)windowStyle qPlatformWindow:(QCocoaWindow *)qpw; @@ -111,6 +112,7 @@ QT_NAMESPACE_ALIAS_OBJC_CLASS(QNSWindow); @property (nonatomic, readonly) QNSWindowHelper *helper; - (id)initWithContentRect:(NSRect)contentRect + screen:(NSScreen*)screen styleMask:(NSUInteger)windowStyle qPlatformWindow:(QCocoaWindow *)qpw; @@ -141,13 +143,20 @@ QT_BEGIN_NAMESPACE // See the qt_on_cocoa manual tests for a working example, located // in tests/manual/cocoa at the time of writing. +#ifdef Q_MOC_RUN +#define Q_NOTIFICATION_HANDLER(notification) Q_INVOKABLE Q_COCOA_NOTIFICATION_##notification +#else +#define Q_NOTIFICATION_HANDLER(notification) +#define Q_NOTIFICATION_PREFIX QT_STRINGIFY2(Q_COCOA_NOTIFICATION_) +#endif + class QCocoaMenuBar; class QCocoaWindow : public QObject, public QPlatformWindow { Q_OBJECT public: - QCocoaWindow(QWindow *tlw); + QCocoaWindow(QWindow *tlw, WId nativeHandle = 0); ~QCocoaWindow(); void setGeometry(const QRect &rect) Q_DECL_OVERRIDE; @@ -177,6 +186,8 @@ public: QMargins frameMargins() const Q_DECL_OVERRIDE; QSurfaceFormat format() const Q_DECL_OVERRIDE; + bool isForeignWindow() const Q_DECL_OVERRIDE; + void requestActivateWindow() Q_DECL_OVERRIDE; WId winId() const Q_DECL_OVERRIDE; @@ -187,15 +198,30 @@ public: void setEmbeddedInForeignView(bool subwindow); - void windowWillMove(); - void windowDidMove(); - void windowDidResize(); - void windowDidEndLiveResize(); + Q_NOTIFICATION_HANDLER(NSWindowWillMoveNotification) void windowWillMove(); + Q_NOTIFICATION_HANDLER(NSWindowDidMoveNotification) void windowDidMove(); + Q_NOTIFICATION_HANDLER(NSWindowDidResizeNotification) void windowDidResize(); + Q_NOTIFICATION_HANDLER(NSViewFrameDidChangeNotification) void viewDidChangeFrame(); + Q_NOTIFICATION_HANDLER(NSViewGlobalFrameDidChangeNotification) void viewDidChangeGlobalFrame(); + Q_NOTIFICATION_HANDLER(NSWindowDidEndLiveResizeNotification) void windowDidEndLiveResize(); + Q_NOTIFICATION_HANDLER(NSWindowDidBecomeKeyNotification) void windowDidBecomeKey(); + Q_NOTIFICATION_HANDLER(NSWindowDidResignKeyNotification) void windowDidResignKey(); + Q_NOTIFICATION_HANDLER(NSWindowDidMiniaturizeNotification) void windowDidMiniaturize(); + Q_NOTIFICATION_HANDLER(NSWindowDidDeminiaturizeNotification) void windowDidDeminiaturize(); + Q_NOTIFICATION_HANDLER(NSWindowWillEnterFullScreenNotification) void windowWillEnterFullScreen(); + Q_NOTIFICATION_HANDLER(NSWindowDidEnterFullScreenNotification) void windowDidEnterFullScreen(); + Q_NOTIFICATION_HANDLER(NSWindowWillExitFullScreenNotification) void windowWillExitFullScreen(); + Q_NOTIFICATION_HANDLER(NSWindowDidExitFullScreenNotification) void windowDidExitFullScreen(); + Q_NOTIFICATION_HANDLER(NSWindowDidOrderOffScreenNotification) void windowDidOrderOffScreen(); + Q_NOTIFICATION_HANDLER(NSWindowDidOrderOnScreenAndFinishAnimatingNotification) void windowDidOrderOnScreen(); + Q_NOTIFICATION_HANDLER(NSWindowDidChangeOcclusionStateNotification) void windowDidChangeOcclusionState(); + Q_NOTIFICATION_HANDLER(NSWindowDidChangeScreenNotification) void windowDidChangeScreen(); + Q_NOTIFICATION_HANDLER(NSWindowWillCloseNotification) void windowWillClose(); + bool windowShouldClose(); - void windowWillClose(); bool windowIsPopupType(Qt::WindowType type = Qt::Widget) const; - void setSynchedWindowStateFromWindow(); + void reportCurrentWindowState(bool unconditionally = false); NSInteger windowLevel(Qt::WindowFlags flags); NSUInteger windowStyleMask(Qt::WindowFlags flags); @@ -239,19 +265,37 @@ public: static QPoint bottomLeftClippedByNSWindowOffsetStatic(QWindow *window); QPoint bottomLeftClippedByNSWindowOffset() const; + + enum RecreationReason { + RecreationNotNeeded = 0, + ParentChanged = 0x1, + MissingWindow = 0x2, + WindowModalityChanged = 0x4, + ChildNSWindowChanged = 0x8, + ContentViewChanged = 0x10, + PanelChanged = 0x20, + }; + Q_DECLARE_FLAGS(RecreationReasons, RecreationReason) + Q_FLAG(RecreationReasons) + protected: - void recreateWindow(const QPlatformWindow *parentWindow); - QCocoaNSWindow *createNSWindow(); - void setNSWindow(QCocoaNSWindow *window); + bool isChildNSWindow() const; + bool isContentView() const; + + void foreachChildNSWindow(void (^block)(QCocoaWindow *)); - bool shouldUseNSPanel(); + void recreateWindowIfNeeded(); + QCocoaNSWindow *createNSWindow(bool shouldBeChildNSWindow, bool shouldBePanel); QRect nativeWindowGeometry() const; - QCocoaWindow *parentCocoaWindow() const; - void syncWindowState(Qt::WindowState newState); void reinsertChildWindow(QCocoaWindow *child); void removeChildWindow(QCocoaWindow *child); - bool isNativeWindowTypeInconsistent(); + + Qt::WindowState windowState() const; + void applyWindowState(Qt::WindowState newState); + void toggleMaximized(); + void toggleFullScreen(); + bool isTransitioningToFullScreen() const; // private: public: // for QNSView @@ -268,13 +312,8 @@ public: // for QNSView bool m_viewIsEmbedded; // true if the m_view is actually embedded in a "foreign" NSView hiearchy bool m_viewIsToBeEmbedded; // true if the m_view is intended to be embedded in a "foreign" NSView hiearchy - QCocoaWindow *m_parentCocoaWindow; - bool m_isNSWindowChild; // this window is a non-top level QWindow with a NSWindow. - QList<QCocoaWindow *> m_childWindows; - Qt::WindowFlags m_windowFlags; - bool m_effectivelyMaximized; - Qt::WindowState m_synchedWindowState; + Qt::WindowState m_lastReportedWindowState; Qt::WindowModality m_windowModality; QPointer<QWindow> m_enterLeaveTargetWindow; bool m_windowUnderMouse; @@ -308,11 +347,6 @@ public: // for QNSView int m_topContentBorderThickness; int m_bottomContentBorderThickness; - // used by showFullScreen in fake mode - QRect m_normalGeometry; - Qt::WindowFlags m_oldWindowFlags; - NSApplicationPresentationOptions m_presentationOptions; - struct BorderRange { BorderRange(quintptr i, int u, int l) : identifier(i), upper(u), lower(l) { } quintptr identifier; diff --git a/src/plugins/platforms/cocoa/qcocoawindow.mm b/src/plugins/platforms/cocoa/qcocoawindow.mm index 40666772c5..f6606745f1 100644 --- a/src/plugins/platforms/cocoa/qcocoawindow.mm +++ b/src/plugins/platforms/cocoa/qcocoawindow.mm @@ -87,6 +87,36 @@ static void qt_closePopups() } } +@interface NSWindow (FullScreenProperty) +@property(readonly) BOOL qt_fullScreen; +@end + +@implementation NSWindow (FullScreenProperty) + ++ (void)load +{ + NSNotificationCenter *center = [NSNotificationCenter defaultCenter]; + [center addObserverForName:NSWindowDidEnterFullScreenNotification object:nil queue:nil + usingBlock:^(NSNotification *notification) { + objc_setAssociatedObject(notification.object, @selector(qt_fullScreen), + [NSNumber numberWithBool:YES], OBJC_ASSOCIATION_RETAIN); + } + ]; + [center addObserverForName:NSWindowDidExitFullScreenNotification object:nil queue:nil + usingBlock:^(NSNotification *notification) { + objc_setAssociatedObject(notification.object, @selector(qt_fullScreen), + nil, OBJC_ASSOCIATION_RETAIN); + } + ]; +} + +- (BOOL)qt_fullScreen +{ + NSNumber *number = objc_getAssociatedObject(self, @selector(qt_fullScreen)); + return [number boolValue]; +} +@end + @implementation QNSWindowHelper @synthesize window = _window; @@ -130,8 +160,7 @@ static void qt_closePopups() [forwardView mouseDragged:theEvent]; } } - - if (!pw->m_isNSWindowChild && theEvent.type == NSLeftMouseDown) { + if (pw->window()->isTopLevel() && theEvent.type == NSLeftMouseDown) { pw->m_forwardWindow.clear(); } } @@ -202,13 +231,14 @@ static void qt_closePopups() @synthesize helper = _helper; - (id)initWithContentRect:(NSRect)contentRect + screen:(NSScreen*)screen styleMask:(NSUInteger)windowStyle qPlatformWindow:(QCocoaWindow *)qpw { self = [super initWithContentRect:contentRect styleMask:windowStyle backing:NSBackingStoreBuffered - defer:NO]; // Deferring window creation breaks OpenGL (the GL context is + defer:NO screen:screen]; // Deferring window creation breaks OpenGL (the GL context is // set up before the window is shown and needs a proper window) if (self) { @@ -222,7 +252,7 @@ static void qt_closePopups() // Prevent child NSWindows from becoming the key window in // order keep the active apperance of the top-level window. QCocoaWindow *pw = self.helper.platformWindow; - if (!pw || pw->m_isNSWindowChild) + if (!pw || !pw->window()->isTopLevel()) return NO; if (pw->shouldRefuseKeyWindowAndFirstResponder()) @@ -241,7 +271,7 @@ static void qt_closePopups() // Windows with a transient parent (such as combobox popup windows) // cannot become the main window: QCocoaWindow *pw = self.helper.platformWindow; - if (!pw || pw->m_isNSWindowChild || pw->window()->transientParent()) + if (!pw || !pw->window()->isTopLevel() || pw->window()->transientParent()) canBecomeMain = NO; return canBecomeMain; @@ -284,13 +314,14 @@ static void qt_closePopups() @synthesize helper = _helper; - (id)initWithContentRect:(NSRect)contentRect + screen:(NSScreen*)screen styleMask:(NSUInteger)windowStyle qPlatformWindow:(QCocoaWindow *)qpw { self = [super initWithContentRect:contentRect styleMask:windowStyle backing:NSBackingStoreBuffered - defer:NO]; // Deferring window creation breaks OpenGL (the GL context is + defer:NO screen:screen]; // Deferring window creation breaks OpenGL (the GL context is // set up before the window is shown and needs a proper window) if (self) { @@ -343,18 +374,72 @@ static void qt_closePopups() @end +static void qRegisterNotificationCallbacks() +{ + static const QLatin1String notificationHandlerPrefix(Q_NOTIFICATION_PREFIX); + + NSNotificationCenter *center = [NSNotificationCenter defaultCenter]; + + const QMetaObject *metaObject = QMetaType::metaObjectForType(qRegisterMetaType<QCocoaWindow*>()); + Q_ASSERT(metaObject); + + for (int i = 0; i < metaObject->methodCount(); ++i) { + QMetaMethod method = metaObject->method(i); + const QString methodTag = QString::fromLatin1(method.tag()); + if (!methodTag.startsWith(notificationHandlerPrefix)) + continue; + + const QString notificationName = methodTag.mid(notificationHandlerPrefix.size()); + [center addObserverForName:notificationName.toNSString() object:nil queue:nil + usingBlock:^(NSNotification *notification) { + + NSView *view = nullptr; + if ([notification.object isKindOfClass:[NSWindow class]]) { + NSWindow *window = notification.object; + // Only top level NSWindows should notify their QNSViews + if (window.parentWindow) + return; + + if (!window.contentView) + return; + + view = window.contentView; + } else if ([notification.object isKindOfClass:[NSView class]]) { + view = notification.object; + } else { + qCWarning(lcQpaCocoaWindow) << "Unhandled notifcation" + << notification.name << "for" << notification.object; + return; + } + Q_ASSERT(view); + + QCocoaWindow *cocoaWindow = nullptr; + if (QNSView *qnsView = qnsview_cast(view)) + cocoaWindow = qnsView.platformWindow; + + // FIXME: Could be a foreign window, look up by iterating top level QWindows + + if (!cocoaWindow) + return; + + if (!method.invoke(cocoaWindow, Qt::DirectConnection)) { + qCWarning(lcQpaCocoaWindow) << "Failed to invoke NSNotification callback for" + << notification.name << "on" << cocoaWindow; + } + }]; + } +} +Q_CONSTRUCTOR_FUNCTION(qRegisterNotificationCallbacks) + const int QCocoaWindow::NoAlertRequest = -1; -QCocoaWindow::QCocoaWindow(QWindow *tlw) +QCocoaWindow::QCocoaWindow(QWindow *tlw, WId nativeHandle) : QPlatformWindow(tlw) , m_view(nil) , m_nsWindow(0) , m_viewIsEmbedded(false) , m_viewIsToBeEmbedded(false) - , m_parentCocoaWindow(0) - , m_isNSWindowChild(false) - , m_effectivelyMaximized(false) - , m_synchedWindowState(Qt::WindowActive) + , m_lastReportedWindowState(Qt::WindowNoState) , m_windowModality(Qt::NonModal) , m_windowUnderMouse(false) , m_inConstructor(true) @@ -379,15 +464,15 @@ QCocoaWindow::QCocoaWindow(QWindow *tlw) , m_drawContentBorderGradient(false) , m_topContentBorderThickness(0) , m_bottomContentBorderThickness(0) - , m_normalGeometry(QRect(0,0,-1,-1)) , m_hasWindowFilePath(false) { qCDebug(lcQpaCocoaWindow) << "QCocoaWindow::QCocoaWindow" << window(); QMacAutoReleasePool pool; - if (tlw->type() == Qt::ForeignWindow) { - m_view = (NSView *)WId(tlw->property("_q_foreignWinId").value<WId>()); + if (nativeHandle) { + m_view = reinterpret_cast<NSView *>(nativeHandle); + [m_view retain]; } else { m_view = [[QNSView alloc] initWithCocoaWindow:this]; // Enable high-dpi OpenGL for retina displays. Enabling has the side @@ -405,7 +490,7 @@ QCocoaWindow::QCocoaWindow(QWindow *tlw) [m_view setWantsLayer:enable]; } setGeometry(tlw->geometry()); - recreateWindow(QPlatformWindow::parent()); + recreateWindowIfNeeded(); tlw->setGeometry(geometry()); if (tlw->isTopLevel()) setWindowIcon(tlw->icon()); @@ -420,18 +505,16 @@ QCocoaWindow::~QCocoaWindow() [m_nsWindow makeFirstResponder:nil]; [m_nsWindow setContentView:nil]; [m_nsWindow.helper detachFromPlatformWindow]; - if (m_isNSWindowChild) { - if (m_parentCocoaWindow) - m_parentCocoaWindow->removeChildWindow(this); - } else if ([m_view superview]) { + if (m_view.window.parentWindow) + [m_view.window.parentWindow removeChildWindow:m_view.window]; + else if ([m_view superview]) [m_view removeFromSuperview]; - } removeMonitor(); // Make sure to disconnect observer in all case if view is valid // to avoid notifications received when deleting when using Qt::AA_NativeWindows attribute - if (window()->type() != Qt::ForeignWindow) + if (!isForeignWindow()) [[NSNotificationCenter defaultCenter] removeObserver:m_view]; // While it is unlikely that this window will be in the popup stack @@ -440,10 +523,9 @@ QCocoaWindow::~QCocoaWindow() QCocoaIntegration::instance()->popupWindowStack()->removeAll(this); } - foreach (QCocoaWindow *child, m_childWindows) { - [m_nsWindow removeChildWindow:child->m_nsWindow]; - child->m_parentCocoaWindow = 0; - } + foreachChildNSWindow(^(QCocoaWindow *childWindow) { + [m_nsWindow removeChildWindow:childWindow->m_nsWindow]; + }); [m_view release]; [m_nsWindow release]; @@ -481,6 +563,11 @@ void QCocoaWindow::setGeometry(const QRect &rectIn) setCocoaGeometry(rect); } +bool QCocoaWindow::isForeignWindow() const +{ + return ![m_view isKindOfClass:[QNSView class]]; +} + QRect QCocoaWindow::geometry() const { // QWindows that are embedded in a NSView hiearchy may be considered @@ -491,7 +578,7 @@ QRect QCocoaWindow::geometry() const NSRect screenRect = [[m_view window] convertRectToScreen:NSMakeRect(windowPoint.x, windowPoint.y, 1, 1)]; NSPoint screenPoint = screenRect.origin; QPoint position = qt_mac_flipPoint(screenPoint).toPoint(); - QSize size = QRectF::fromCGRect([m_view bounds]).toRect().size(); + QSize size = QRectF::fromCGRect(NSRectToCGRect([m_view bounds])).toRect().size(); return QRect(position, size); } @@ -504,7 +591,7 @@ void QCocoaWindow::setCocoaGeometry(const QRect &rect) QMacAutoReleasePool pool; if (m_viewIsEmbedded) { - if (window()->type() != Qt::ForeignWindow) { + if (!isForeignWindow()) { [m_view setFrame:NSMakeRect(0, 0, rect.width(), rect.height())]; } else { QPlatformWindow::setGeometry(rect); @@ -512,9 +599,9 @@ void QCocoaWindow::setCocoaGeometry(const QRect &rect) return; } - if (m_isNSWindowChild) { + if (isChildNSWindow()) { QPlatformWindow::setGeometry(rect); - NSWindow *parentNSWindow = m_parentCocoaWindow->m_nsWindow; + NSWindow *parentNSWindow = m_view.window.parentWindow; NSRect parentWindowFrame = [parentNSWindow contentRectForFrameRect:parentNSWindow.frame]; clipWindow(parentWindowFrame); @@ -528,7 +615,7 @@ void QCocoaWindow::setCocoaGeometry(const QRect &rect) [m_view setFrame:NSMakeRect(rect.x(), rect.y(), rect.width(), rect.height())]; } - if (window()->type() == Qt::ForeignWindow) + if (isForeignWindow()) QPlatformWindow::setGeometry(rect); // will call QPlatformWindow::setGeometry(rect) during resize confirmation (see qnsview.mm) @@ -536,14 +623,14 @@ void QCocoaWindow::setCocoaGeometry(const QRect &rect) void QCocoaWindow::clipChildWindows() { - foreach (QCocoaWindow *childWindow, m_childWindows) { + foreachChildNSWindow(^(QCocoaWindow *childWindow) { childWindow->clipWindow(m_nsWindow.frame); - } + }); } void QCocoaWindow::clipWindow(const NSRect &clipRect) { - if (!m_isNSWindowChild) + if (!isChildNSWindow()) return; NSRect clippedWindowRect = NSZeroRect; @@ -568,15 +655,15 @@ void QCocoaWindow::clipWindow(const NSRect &clipRect) m_hiddenByClipping = false; if (!m_hiddenByAncestor) { [m_nsWindow orderFront:nil]; - m_parentCocoaWindow->reinsertChildWindow(this); + static_cast<QCocoaWindow *>(QPlatformWindow::parent())->reinsertChildWindow(this); } } } // recurse - foreach (QCocoaWindow *childWindow, m_childWindows) { + foreachChildNSWindow(^(QCocoaWindow *childWindow) { childWindow->clipWindow(clippedWindowRect); - } + }); } void QCocoaWindow::hide(bool becauseOfAncestor) @@ -593,8 +680,9 @@ void QCocoaWindow::hide(bool becauseOfAncestor) if (!visible) // Could have been clipped before return; - foreach (QCocoaWindow *childWindow, m_childWindows) + foreachChildNSWindow(^(QCocoaWindow *childWindow) { childWindow->hide(true); + }); [m_nsWindow orderOut:nil]; } @@ -604,20 +692,21 @@ void QCocoaWindow::show(bool becauseOfAncestor) if ([m_nsWindow isVisible]) return; - if (m_parentCocoaWindow && ![m_parentCocoaWindow->m_nsWindow isVisible]) { + if (m_view.window.parentWindow && !m_view.window.parentWindow.visible) { m_hiddenByAncestor = true; // Parent still hidden, don't show now } else if ((becauseOfAncestor == m_hiddenByAncestor) // Was NEITHER explicitly hidden && !m_hiddenByClipping) { // ... NOR clipped - if (m_isNSWindowChild) { + if (isChildNSWindow()) { m_hiddenByAncestor = false; setCocoaGeometry(windowGeometry()); } if (!m_hiddenByClipping) { // setCocoaGeometry() can change the clipping status [m_nsWindow orderFront:nil]; - if (m_isNSWindowChild) - m_parentCocoaWindow->reinsertChildWindow(this); - foreach (QCocoaWindow *childWindow, m_childWindows) + if (isChildNSWindow()) + static_cast<QCocoaWindow *>(QPlatformWindow::parent())->reinsertChildWindow(this); + foreachChildNSWindow(^(QCocoaWindow *childWindow) { childWindow->show(true); + }); } } } @@ -626,7 +715,7 @@ void QCocoaWindow::setVisible(bool visible) { qCDebug(lcQpaCocoaWindow) << "QCocoaWindow::setVisible" << window() << visible; - if (m_isNSWindowChild && m_hiddenByClipping) + if (isChildNSWindow() && m_hiddenByClipping) return; m_inSetVisible = true; @@ -638,8 +727,7 @@ void QCocoaWindow::setVisible(bool visible) if (visible) { // We need to recreate if the modality has changed as the style mask will need updating - if (m_windowModality != window()->modality() || isNativeWindowTypeInconsistent()) - recreateWindow(QPlatformWindow::parent()); + recreateWindowIfNeeded(); // Register popup windows. The Cocoa platform plugin will forward mouse events // to them and close them when needed. @@ -674,14 +762,14 @@ void QCocoaWindow::setVisible(bool visible) // setWindowState might have been called while the window was hidden and // will not change the NSWindow state in that case. Sync up here: - syncWindowState(window()->windowState()); + applyWindowState(window()->windowState()); if (window()->windowState() != Qt::WindowMinimized) { if ((window()->modality() == Qt::WindowModal || window()->type() == Qt::Sheet) && parentCocoaWindow) { // show the window as a sheet - [NSApp beginSheet:m_nsWindow modalForWindow:parentCocoaWindow->m_nsWindow modalDelegate:nil didEndSelector:nil contextInfo:nil]; + [parentCocoaWindow->m_nsWindow beginSheet:m_nsWindow completionHandler:nil]; } else if (window()->modality() != Qt::NonModal) { // show the window as application modal QCocoaEventDispatcher *cocoaEventDispatcher = qobject_cast<QCocoaEventDispatcher *>(QGuiApplication::instance()->eventDispatcher()); @@ -700,8 +788,9 @@ void QCocoaWindow::setVisible(bool visible) else [m_nsWindow orderFront:nil]; - foreach (QCocoaWindow *childWindow, m_childWindows) + foreachChildNSWindow(^(QCocoaWindow *childWindow) { childWindow->show(true); + }); } else { show(); } @@ -742,8 +831,10 @@ void QCocoaWindow::setVisible(bool visible) cocoaEventDispatcherPrivate->endModalSession(window()); m_hasModalSession = false; } else { - if ([m_nsWindow isSheet]) - [NSApp endSheet:m_nsWindow]; + if ([m_nsWindow isSheet]) { + Q_ASSERT_X(parentCocoaWindow, "QCocoaWindow", "Window modal dialog has no transient parent."); + [parentCocoaWindow->m_nsWindow endSheet:m_nsWindow]; + } } hide(); @@ -856,6 +947,10 @@ NSUInteger QCocoaWindow::windowStyleMask(Qt::WindowFlags flags) if (m_drawContentBorderGradient) styleMask |= NSTexturedBackgroundWindowMask; + // Don't wipe fullscreen state + if (m_nsWindow.styleMask & NSFullScreenWindowMask) + styleMask |= NSFullScreenWindowMask; + return styleMask; } @@ -873,13 +968,14 @@ void QCocoaWindow::setWindowZoomButton(Qt::WindowFlags flags) // in line with the platform style guidelines. bool fixedSizeNoZoom = (windowMinimumSize().isValid() && windowMaximumSize().isValid() && windowMinimumSize() == windowMaximumSize()); - bool customizeNoZoom = ((flags & Qt::CustomizeWindowHint) && !(flags & Qt::WindowMaximizeButtonHint)); + bool customizeNoZoom = ((flags & Qt::CustomizeWindowHint) + && !(flags & (Qt::WindowMaximizeButtonHint | Qt::WindowFullscreenButtonHint))); [[m_nsWindow standardWindowButton:NSWindowZoomButton] setEnabled:!(fixedSizeNoZoom || customizeNoZoom)]; } void QCocoaWindow::setWindowFlags(Qt::WindowFlags flags) { - if (m_nsWindow && !m_isNSWindowChild) { + if (m_nsWindow && !isChildNSWindow()) { NSUInteger styleMask = windowStyleMask(flags); NSInteger level = this->windowLevel(flags); // While setting style mask we can have -updateGeometry calls on a content @@ -908,13 +1004,16 @@ void QCocoaWindow::setWindowFlags(Qt::WindowFlags flags) setWindowZoomButton(flags); } + if (m_nsWindow) + m_nsWindow.ignoresMouseEvents = flags & Qt::WindowTransparentForInput; + m_windowFlags = flags; } void QCocoaWindow::setWindowState(Qt::WindowState state) { if (window()->isVisible()) - syncWindowState(state); // Window state set for hidden windows take effect when show() is called. + applyWindowState(state); // Window state set for hidden windows take effect when show() is called } void QCocoaWindow::setWindowTitle(const QString &title) @@ -983,19 +1082,16 @@ void QCocoaWindow::raise() // ### handle spaces (see Qt 4 raise_sys in qwidget_mac.mm) if (!m_nsWindow) return; - if (m_isNSWindowChild) { - QList<QCocoaWindow *> &siblings = m_parentCocoaWindow->m_childWindows; - siblings.removeOne(this); - siblings.append(this); + if (isChildNSWindow()) { if (m_hiddenByClipping) return; } if ([m_nsWindow isVisible]) { - if (m_isNSWindowChild) { + if (isChildNSWindow()) { // -[NSWindow orderFront:] doesn't work with attached windows. // The only solution is to remove and add the child window. // This will place it on top of all the other NSWindows. - NSWindow *parentNSWindow = m_parentCocoaWindow->m_nsWindow; + NSWindow *parentNSWindow = m_view.window.parentWindow; [parentNSWindow removeChildWindow:m_nsWindow]; [parentNSWindow addChildWindow:m_nsWindow ordered:NSWindowAbove]; } else { @@ -1021,20 +1117,17 @@ void QCocoaWindow::lower() qCDebug(lcQpaCocoaWindow) << "QCocoaWindow::lower" << window(); if (!m_nsWindow) return; - if (m_isNSWindowChild) { - QList<QCocoaWindow *> &siblings = m_parentCocoaWindow->m_childWindows; - siblings.removeOne(this); - siblings.prepend(this); + if (isChildNSWindow()) { if (m_hiddenByClipping) return; } if ([m_nsWindow isVisible]) { - if (m_isNSWindowChild) { + if (isChildNSWindow()) { // -[NSWindow orderBack:] doesn't work with attached windows. // The only solution is to remove and add all the child windows except this one. // This will keep the current window at the bottom while adding the others on top of it, // hopefully in the same order (this is not documented anywhere in the Cocoa documentation). - NSWindow *parentNSWindow = m_parentCocoaWindow->m_nsWindow; + NSWindow *parentNSWindow = m_view.window.parentWindow; NSArray *children = [parentNSWindow.childWindows copy]; for (NSWindow *child in children) if (m_nsWindow != child) { @@ -1095,7 +1188,7 @@ void QCocoaWindow::propagateSizeHints() QSize sizeIncrement = windowSizeIncrement(); if (sizeIncrement.isEmpty()) sizeIncrement = QSize(1, 1); - [m_nsWindow setResizeIncrements:sizeIncrement.toCGSize()]; + [m_nsWindow setResizeIncrements:NSSizeFromCGSize(sizeIncrement.toCGSize())]; QRect rect = geometry(); QSize baseSize = windowBaseSize(); @@ -1158,7 +1251,7 @@ void QCocoaWindow::setParent(const QPlatformWindow *parentWindow) // recreate the window for compatibility bool unhideAfterRecreate = parentWindow && !m_viewIsToBeEmbedded && ![m_view isHidden]; - recreateWindow(parentWindow); + recreateWindowIfNeeded(); if (unhideAfterRecreate) [m_view setHidden:NO]; setCocoaGeometry(geometry()); @@ -1182,6 +1275,8 @@ void QCocoaWindow::setEmbeddedInForeignView(bool embedded) m_nsWindow = 0; } +// ----------------------- NSWindow notifications ----------------------- + void QCocoaWindow::windowWillMove() { // Close any open popups on window move @@ -1190,10 +1285,13 @@ void QCocoaWindow::windowWillMove() void QCocoaWindow::windowDidMove() { - if (m_isNSWindowChild) + if (isChildNSWindow()) return; [qnsview_cast(m_view) updateGeometry]; + + // Moving a window might bring it out of maximized state + reportCurrentWindowState(); } void QCocoaWindow::windowDidResize() @@ -1201,21 +1299,172 @@ void QCocoaWindow::windowDidResize() if (!m_nsWindow) return; - if (m_isNSWindowChild) + if (isChildNSWindow()) return; clipChildWindows(); [qnsview_cast(m_view) updateGeometry]; + + if (!m_view.inLiveResize) + reportCurrentWindowState(); +} + +void QCocoaWindow::viewDidChangeFrame() +{ + [qnsview_cast(m_view) updateGeometry]; +} + +/*! + Callback for NSViewGlobalFrameDidChangeNotification. + + Posted whenever an NSView object that has attached surfaces (that is, + NSOpenGLContext objects) moves to a different screen, or other cases + where the NSOpenGLContext object needs to be updated. +*/ +void QCocoaWindow::viewDidChangeGlobalFrame() +{ + updateExposedGeometry(); } void QCocoaWindow::windowDidEndLiveResize() { - if (m_synchedWindowState == Qt::WindowMaximized && ![m_nsWindow isZoomed]) { - m_effectivelyMaximized = false; - [qnsview_cast(m_view) notifyWindowStateChanged:Qt::WindowNoState]; + reportCurrentWindowState(); +} + +void QCocoaWindow::windowDidBecomeKey() +{ + if (isForeignWindow()) + return; + + if (m_windowUnderMouse) { + QPointF windowPoint; + QPointF screenPoint; + [qnsview_cast(m_view) convertFromScreen:[NSEvent mouseLocation] toWindowPoint:&windowPoint andScreenPoint:&screenPoint]; + QWindowSystemInterface::handleEnterEvent(m_enterLeaveTargetWindow, windowPoint, screenPoint); + } + + if (!windowIsPopupType() && !qnsview_cast(m_view).isMenuView) + QWindowSystemInterface::handleWindowActivated(window()); +} + +void QCocoaWindow::windowDidResignKey() +{ + if (isForeignWindow()) + return; + + // Key window will be non-nil if another window became key, so do not + // set the active window to zero here -- the new key window's + // NSWindowDidBecomeKeyNotification hander will change the active window. + NSWindow *keyWindow = [NSApp keyWindow]; + if (!keyWindow || keyWindow == m_view.window) { + // No new key window, go ahead and set the active window to zero + if (!windowIsPopupType() && !qnsview_cast(m_view).isMenuView) + QWindowSystemInterface::handleWindowActivated(0); + } +} + +void QCocoaWindow::windowDidMiniaturize() +{ + reportCurrentWindowState(); +} + +void QCocoaWindow::windowDidDeminiaturize() +{ + reportCurrentWindowState(); +} + +void QCocoaWindow::windowWillEnterFullScreen() +{ + // The NSWindow needs to be resizable, otherwise we'll end up with + // the normal window geometry, centered in the middle of the screen + // on a black background. The styleMask will be reset below. + m_nsWindow.styleMask |= NSResizableWindowMask; +} + +void QCocoaWindow::windowDidEnterFullScreen() +{ + Q_ASSERT_X(m_nsWindow.qt_fullScreen, "QCocoaWindow", + "FullScreen category processes window notifications first"); + + // Reset to original styleMask + setWindowFlags(m_windowFlags); + + reportCurrentWindowState(); +} + +void QCocoaWindow::windowWillExitFullScreen() +{ + // The NSWindow needs to be resizable, otherwise we'll end up with + // a weird zoom animation. The styleMask will be reset below. + m_nsWindow.styleMask |= NSResizableWindowMask; +} + +void QCocoaWindow::windowDidExitFullScreen() +{ + Q_ASSERT_X(!m_nsWindow.qt_fullScreen, "QCocoaWindow", + "FullScreen category processes window notifications first"); + + // Reset to original styleMask + setWindowFlags(m_windowFlags); + + Qt::WindowState requestedState = window()->windowState(); + + // Deliver update of QWindow state + reportCurrentWindowState(); + + if (requestedState != windowState() && requestedState != Qt::WindowFullScreen) { + // We were only going out of full screen as an intermediate step before + // progressing into the final step, so re-sync the desired state. + applyWindowState(requestedState); + } +} + +void QCocoaWindow::windowDidOrderOffScreen() +{ + obscureWindow(); +} + +void QCocoaWindow::windowDidOrderOnScreen() +{ + exposeWindow(); +} + +void QCocoaWindow::windowDidChangeOcclusionState() +{ + // Several unit tests expect paint and/or expose events for windows that are + // sometimes (unpredictably) occluded and some unit tests depend on QWindow::isExposed. + // Don't send Expose/Obscure events when running under QTestLib. + static const bool onTestLib = qt_mac_resolveOption(false, "QT_QTESTLIB_RUNNING"); + if (!onTestLib) { + if ((NSUInteger)[m_view.window occlusionState] & NSWindowOcclusionStateVisible) { + exposeWindow(); + } else { + // Send Obscure events on window occlusion to stop animations. + obscureWindow(); + } } } +void QCocoaWindow::windowDidChangeScreen() +{ + if (!window()) + return; + + if (QCocoaScreen *cocoaScreen = QCocoaIntegration::instance()->screenForNSScreen(m_view.window.screen)) + QWindowSystemInterface::handleWindowScreenChanged(window(), cocoaScreen->screen()); + + updateExposedGeometry(); +} + +void QCocoaWindow::windowWillClose() +{ + // Close any open popups on window closing. + if (window() && !windowIsPopupType(window()->type())) + qt_closePopups(); +} + +// ----------------------- NSWindowDelegate callbacks ----------------------- + bool QCocoaWindow::windowShouldClose() { qCDebug(lcQpaCocoaWindow) << "QCocoaWindow::windowShouldClose" << window(); @@ -1229,18 +1478,7 @@ bool QCocoaWindow::windowShouldClose() return accepted; } -void QCocoaWindow::windowWillClose() -{ - // Close any open popups on window closing. - if (window() && !windowIsPopupType(window()->type())) - qt_closePopups(); -} - -void QCocoaWindow::setSynchedWindowStateFromWindow() -{ - if (QWindow *w = window()) - m_synchedWindowState = w->windowState(); -} +// -------------------------------------------------------------------------- bool QCocoaWindow::windowIsPopupType(Qt::WindowType type) const { @@ -1264,62 +1502,155 @@ QCocoaGLContext *QCocoaWindow::currentContext() const } #endif -void QCocoaWindow::recreateWindow(const QPlatformWindow *parentWindow) +/*! + Checks if the window is a non-top level QWindow with a NSWindow. + + \sa _q_platform_MacUseNSWindow, QT_MAC_USE_NSWINDOW +*/ +bool QCocoaWindow::isChildNSWindow() const +{ + return m_view.window.parentWindow != nil; +} + +/*! + Checks if the window is the content view of its immediate NSWindow. + + Being the content view of a NSWindow means the QWindow is + the highest accessible NSView object in the window's view + hierarchy. + + This can only happen in two cases, either if the QWindow is + itself a top level window, or if it's a child NSWindow. + + \sa isChildNSWindow +*/ +bool QCocoaWindow::isContentView() const +{ + return m_view.window.contentView == m_view; +} + +/*! + Iterates child NSWindows that have a corresponding QCocoaWindow. +*/ +void QCocoaWindow::foreachChildNSWindow(void (^block)(QCocoaWindow *)) { - qCDebug(lcQpaCocoaWindow) << "QCocoaWindow::recreateWindow" << window() + NSArray *windows = m_view.window.childWindows; + [windows enumerateObjectsUsingBlock:^(NSWindow *window, NSUInteger index, BOOL *stop) { + Q_UNUSED(index); + Q_UNUSED(stop); + if (QNSView *view = qnsview_cast(window.contentView)) + block(view.platformWindow); + }]; +} + +/*! + Recreates (or removes) the NSWindow for this QWindow, if needed. + + A QWindow may need a corresponding NSWindow, depending on whether + or not it's a top level or not (or explicitly set to be a child + NSWindow), whether it is a NSPanel or not, etc. +*/ +void QCocoaWindow::recreateWindowIfNeeded() +{ + QPlatformWindow *parentWindow = QPlatformWindow::parent(); + qCDebug(lcQpaCocoaWindow) << "QCocoaWindow::recreateWindowIfNeeded" << window() << "parent" << (parentWindow ? parentWindow->window() : 0); - bool wasNSWindowChild = m_isNSWindowChild; - BOOL requestNSWindowChild = qt_mac_resolveOption(NO, window(), "_q_platform_MacUseNSWindow", - "QT_MAC_USE_NSWINDOW"); - m_isNSWindowChild = parentWindow && requestNSWindowChild; - bool needsNSWindow = m_isNSWindowChild || !parentWindow; + RecreationReasons recreateReason = RecreationNotNeeded; + + QCocoaWindow *oldParentCocoaWindow = nullptr; + if (QNSView *qnsView = qnsview_cast(m_view.superview)) + oldParentCocoaWindow = qnsView.platformWindow; + + if (parentWindow != oldParentCocoaWindow) + recreateReason |= ParentChanged; + + if (!m_view.window) + recreateReason |= MissingWindow; + + // If the modality has changed the style mask will need updating + if (m_windowModality != window()->modality()) + recreateReason |= WindowModalityChanged; + + const bool shouldBeChildNSWindow = parentWindow && qt_mac_resolveOption(NO, + window(), "_q_platform_MacUseNSWindow", "QT_MAC_USE_NSWINDOW"); + + if (isChildNSWindow() != shouldBeChildNSWindow) + recreateReason |= ChildNSWindowChanged; + + const bool shouldBeContentView = !parentWindow || shouldBeChildNSWindow; + if (isContentView() != shouldBeContentView) + recreateReason |= ContentViewChanged; + + Qt::WindowType type = window()->type(); + const bool isPanel = isContentView() && [m_view.window isKindOfClass:[QNSPanel class]]; + const bool shouldBePanel = shouldBeContentView && !shouldBeChildNSWindow && + ((type & Qt::Popup) == Qt::Popup || (type & Qt::Dialog) == Qt::Dialog); + + if (isPanel != shouldBePanel) + recreateReason |= PanelChanged; + + if (recreateReason == RecreationNotNeeded) { + qCDebug(lcQpaCocoaWindow) << "No need to recreate NSWindow"; + return; + } + + qCDebug(lcQpaCocoaWindow) << "Recreating NSWindow due to" << recreateReason; - QCocoaWindow *oldParentCocoaWindow = m_parentCocoaWindow; - m_parentCocoaWindow = const_cast<QCocoaWindow *>(static_cast<const QCocoaWindow *>(parentWindow)); - if (m_parentCocoaWindow && m_isNSWindowChild) { - QWindow *parentQWindow = m_parentCocoaWindow->window(); + QCocoaWindow *parentCocoaWindow = static_cast<QCocoaWindow *>(parentWindow); + + if (shouldBeChildNSWindow) { + QWindow *parentQWindow = parentWindow->window(); + // Ensure that all parents in the hierarchy are also child NSWindows if (!parentQWindow->property("_q_platform_MacUseNSWindow").toBool()) { parentQWindow->setProperty("_q_platform_MacUseNSWindow", QVariant(true)); - m_parentCocoaWindow->recreateWindow(m_parentCocoaWindow->m_parentCocoaWindow); + parentCocoaWindow->recreateWindowIfNeeded(); } } - bool usesNSPanel = [m_nsWindow isKindOfClass:[QNSPanel class]]; - - // No child QNSWindow should notify its QNSView - if (m_nsWindow && (window()->type() != Qt::ForeignWindow) && m_parentCocoaWindow && !oldParentCocoaWindow) - [[NSNotificationCenter defaultCenter] removeObserver:m_view - name:nil object:m_nsWindow]; - // Remove current window (if any) - if ((m_nsWindow && !needsNSWindow) || (usesNSPanel != shouldUseNSPanel())) { + if ((isContentView() && !shouldBeContentView) || (recreateReason & PanelChanged)) { [m_nsWindow closeAndRelease]; - if (wasNSWindowChild && oldParentCocoaWindow) - oldParentCocoaWindow->removeChildWindow(this); + if (isChildNSWindow()) + [m_view.window.parentWindow removeChildWindow:m_view.window]; + if (isContentView()) { + // We explicitly disassociate m_view from the window's contentView, + // as AppKit does not automatically do this in response to removing + // the view from the NSThemeFrame subview list, so we might end up + // with a NSWindow contentView pointing to a deallocated NSView. + m_view.window.contentView = nil; + } m_nsWindow = 0; } - if (needsNSWindow) { + if (shouldBeContentView) { bool noPreviousWindow = m_nsWindow == 0; if (noPreviousWindow) - m_nsWindow = createNSWindow(); - - // Only non-child QNSWindows should notify their QNSViews - // (but don't register more than once). - if ((window()->type() != Qt::ForeignWindow) && (noPreviousWindow || (wasNSWindowChild && !m_isNSWindowChild))) - [[NSNotificationCenter defaultCenter] addObserver:m_view - selector:@selector(windowNotification:) - name:nil // Get all notifications - object:m_nsWindow]; - - if (oldParentCocoaWindow) { - if (!m_isNSWindowChild || oldParentCocoaWindow != m_parentCocoaWindow) - oldParentCocoaWindow->removeChildWindow(this); + m_nsWindow = createNSWindow(shouldBeChildNSWindow, shouldBePanel); + + if (m_view.window.parentWindow) { + if (!shouldBeChildNSWindow || (recreateReason & ParentChanged)) + [m_view.window.parentWindow removeChildWindow:m_view.window]; m_forwardWindow = oldParentCocoaWindow; } - setNSWindow(m_nsWindow); + // Move view to new NSWindow if needed + if (m_nsWindow.contentView != m_view) { + [m_view setPostsFrameChangedNotifications:NO]; + [m_view retain]; + if (m_view.superview) // m_view comes from another NSWindow + [m_view removeFromSuperview]; + [m_nsWindow setContentView:m_view]; + [m_view release]; + [m_view setPostsFrameChangedNotifications:YES]; + // QTBUG-58963 + // viewDidChangeFrame() should be called for each window automatically at this point because it is + // registered with Q_NOTIFICATION_HANDLER(NSViewFrameDidChangeNotification); + // The corner case when it's not called and we need to make a manual geometry update is when window's + // size is not specified explicitly but minimumSize is set and matches to the size NSView was created with. + if (QSizeF::fromCGSize(m_view.frame.size) == [QNSView defaultViewSize]) + viewDidChangeFrame(); + } } if (m_viewIsToBeEmbedded) { @@ -1330,32 +1661,21 @@ void QCocoaWindow::recreateWindow(const QPlatformWindow *parentWindow) setWindowFlags(window()->flags()); setWindowTitle(window()->title()); setWindowState(window()->windowState()); - } else if (m_isNSWindowChild) { - m_nsWindow.styleMask = NSBorderlessWindowMask; - m_nsWindow.hasShadow = NO; - m_nsWindow.level = NSNormalWindowLevel; - NSWindowCollectionBehavior collectionBehavior = - NSWindowCollectionBehaviorManaged | NSWindowCollectionBehaviorIgnoresCycle - | NSWindowCollectionBehaviorFullScreenAuxiliary; - m_nsWindow.animationBehavior = NSWindowAnimationBehaviorNone; - m_nsWindow.collectionBehavior = collectionBehavior; - setCocoaGeometry(windowGeometry()); - - QList<QCocoaWindow *> &siblings = m_parentCocoaWindow->m_childWindows; - if (siblings.contains(this)) { - if (!m_hiddenByClipping) - m_parentCocoaWindow->reinsertChildWindow(this); - } else { - if (!m_hiddenByClipping) - [m_parentCocoaWindow->m_nsWindow addChildWindow:m_nsWindow ordered:NSWindowAbove]; - siblings.append(this); + } else if (shouldBeChildNSWindow) { + if (!m_hiddenByClipping) { + [parentCocoaWindow->m_nsWindow addChildWindow:m_nsWindow ordered:NSWindowAbove]; + parentCocoaWindow->reinsertChildWindow(this); } + + // Set properties after the window has been made a child NSWindow + setCocoaGeometry(windowGeometry()); + setWindowFlags(window()->flags()); } else { // Child windows have no NSWindow, link the NSViews instead. if ([m_view superview]) [m_view removeFromSuperview]; - [m_parentCocoaWindow->m_view addSubview:m_view]; + [parentCocoaWindow->m_view addSubview:m_view]; QRect rect = windowGeometry(); // Prevent setting a (0,0) window size; causes opengl context // "Invalid Drawable" warnings. @@ -1366,9 +1686,6 @@ void QCocoaWindow::recreateWindow(const QPlatformWindow *parentWindow) [m_view setHidden:!window()->isVisible()]; } - m_nsWindow.ignoresMouseEvents = - (window()->flags() & Qt::WindowTransparentForInput) == Qt::WindowTransparentForInput; - const qreal opacity = qt_window_private(window())->opacity; if (!qFuzzyCompare(opacity, qreal(1.0))) setOpacity(opacity); @@ -1381,11 +1698,17 @@ void QCocoaWindow::recreateWindow(const QPlatformWindow *parentWindow) void QCocoaWindow::reinsertChildWindow(QCocoaWindow *child) { - int childIndex = m_childWindows.indexOf(child); + const QObjectList &childWindows = window()->children(); + int childIndex = childWindows.indexOf(child->window()); Q_ASSERT(childIndex != -1); - for (int i = childIndex; i < m_childWindows.size(); i++) { - NSWindow *nsChild = m_childWindows[i]->m_nsWindow; + for (int i = childIndex; i < childWindows.size(); ++i) { + QWindow *window = static_cast<QWindow *>(childWindows.at(i)); + QCocoaWindow *cocoaWindow = static_cast<QCocoaWindow *>(window->handle()); + if (!cocoaWindow) + continue; + + NSWindow *nsChild = cocoaWindow->m_nsWindow; if (i != childIndex) [m_nsWindow removeChildWindow:nsChild]; [m_nsWindow addChildWindow:nsChild ordered:NSWindowAbove]; @@ -1399,114 +1722,80 @@ void QCocoaWindow::requestActivateWindow() [window makeKeyWindow]; } -bool QCocoaWindow::shouldUseNSPanel() -{ - Qt::WindowType type = window()->type(); - - return !m_isNSWindowChild && - ((type & Qt::Popup) == Qt::Popup || (type & Qt::Dialog) == Qt::Dialog); -} - -QCocoaNSWindow * QCocoaWindow::createNSWindow() +QCocoaNSWindow *QCocoaWindow::createNSWindow(bool shouldBeChildNSWindow, bool shouldBePanel) { QMacAutoReleasePool pool; QRect rect = initialGeometry(window(), windowGeometry(), defaultWindowWidth, defaultWindowHeight); - NSRect frame = qt_mac_flipRect(rect); - - Qt::WindowType type = window()->type(); - Qt::WindowFlags flags = window()->flags(); - NSUInteger styleMask; - if (m_isNSWindowChild) { - styleMask = NSBorderlessWindowMask; - } else { - styleMask = windowStyleMask(flags); + QScreen *targetScreen = nullptr; + for (QScreen *screen : QGuiApplication::screens()) { + if (screen->geometry().contains(rect.topLeft())) { + targetScreen = screen; + break; + } } - QCocoaNSWindow *createdWindow = 0; - - // Use NSPanel for popup-type windows. (Popup, Tool, ToolTip, SplashScreen) - // and dialogs - if (shouldUseNSPanel()) { - QNSPanel *window; - window = [[QNSPanel alloc] initWithContentRect:frame - styleMask: styleMask - qPlatformWindow:this]; - if ((type & Qt::Popup) == Qt::Popup) - [window setHasShadow:YES]; - - // Qt::Tool windows hide on app deactivation, unless Qt::WA_MacAlwaysShowToolWindow is set. - QVariant showWithoutActivating = QPlatformWindow::window()->property("_q_macAlwaysShowToolWindow"); - bool shouldHideOnDeactivate = ((type & Qt::Tool) == Qt::Tool) && - !(showWithoutActivating.isValid() && showWithoutActivating.toBool()); - [window setHidesOnDeactivate: shouldHideOnDeactivate]; - - // Make popup windows show on the same desktop as the parent full-screen window. - [window setCollectionBehavior:NSWindowCollectionBehaviorFullScreenAuxiliary]; - if ((type & Qt::Popup) == Qt::Popup) - [window setAnimationBehavior:NSWindowAnimationBehaviorUtilityWindow]; - - createdWindow = window; - } else { - QNSWindow *window; - window = [[QNSWindow alloc] initWithContentRect:frame - styleMask: styleMask - qPlatformWindow:this]; - createdWindow = window; + + if (!targetScreen) { + qCWarning(lcQpaCocoaWindow) << "Window position outside any known screen, using primary screen"; + targetScreen = QGuiApplication::primaryScreen(); } - if ([createdWindow respondsToSelector:@selector(setRestorable:)]) - [createdWindow setRestorable: NO]; + rect.translate(-targetScreen->geometry().topLeft()); + QCocoaScreen *cocoaScreen = static_cast<QCocoaScreen *>(targetScreen->handle()); + NSRect frame = NSRectFromCGRect(cocoaScreen->mapToNative(rect).toCGRect()); - NSInteger level = windowLevel(flags); - [createdWindow setLevel:level]; + // Note: The macOS window manager has a bug, where if a screen is rotated, it will not allow + // a window to be created within the area of the screen that has a Y coordinate (I quadrant) + // higher than the height of the screen in its non-rotated state, unless the window is + // created with the NSWindowStyleMaskBorderless style mask. - // OpenGL surfaces can be ordered either above(default) or below the NSWindow. - // When ordering below the window must be tranclucent and have a clear background color. - static GLint openglSourfaceOrder = qt_mac_resolveOption(1, "QT_MAC_OPENGL_SURFACE_ORDER"); + Qt::WindowType type = window()->type(); + Qt::WindowFlags flags = window()->flags(); + + // Create NSWindow + Class windowClass = shouldBePanel ? [QNSPanel class] : [QNSWindow class]; + NSUInteger styleMask = shouldBeChildNSWindow ? NSBorderlessWindowMask : windowStyleMask(flags); + QCocoaNSWindow *window = [[windowClass alloc] initWithContentRect:frame + screen:cocoaScreen->nativeScreen() styleMask:styleMask qPlatformWindow:this]; + + window.restorable = NO; + window.level = shouldBeChildNSWindow ? NSNormalWindowLevel : windowLevel(flags); - bool isTranslucent = window()->format().alphaBufferSize() > 0 - || (surface()->supportsOpenGL() && openglSourfaceOrder == -1); - if (isTranslucent) { - [createdWindow setBackgroundColor:[NSColor clearColor]]; - [createdWindow setOpaque:NO]; + if (!isOpaque()) { + window.backgroundColor = [NSColor clearColor]; + window.opaque = NO; } - m_windowModality = window()->modality(); + Q_ASSERT(!(shouldBePanel && shouldBeChildNSWindow)); - applyContentBorderThickness(createdWindow); + if (shouldBePanel) { + // Qt::Tool windows hide on app deactivation, unless Qt::WA_MacAlwaysShowToolWindow is set + window.hidesOnDeactivate = ((type & Qt::Tool) == Qt::Tool) && + !qt_mac_resolveOption(false, QPlatformWindow::window(), "_q_macAlwaysShowToolWindow", ""); - return createdWindow; -} + // Make popup windows show on the same desktop as the parent full-screen window + window.collectionBehavior = NSWindowCollectionBehaviorFullScreenAuxiliary; -void QCocoaWindow::setNSWindow(QCocoaNSWindow *window) -{ - if (window.contentView != m_view) { - [m_view setPostsFrameChangedNotifications:NO]; - [m_view retain]; - if (m_view.superview) // m_view comes from another NSWindow - [m_view removeFromSuperview]; - [window setContentView:m_view]; - [m_view release]; - [m_view setPostsFrameChangedNotifications:YES]; + if ((type & Qt::Popup) == Qt::Popup) { + window.hasShadow = YES; + window.animationBehavior = NSWindowAnimationBehaviorUtilityWindow; + } + } else if (shouldBeChildNSWindow) { + window.collectionBehavior = + NSWindowCollectionBehaviorManaged + | NSWindowCollectionBehaviorIgnoresCycle + | NSWindowCollectionBehaviorFullScreenAuxiliary; + window.hasShadow = NO; + window.animationBehavior = NSWindowAnimationBehaviorNone; } -} - -void QCocoaWindow::removeChildWindow(QCocoaWindow *child) -{ - m_childWindows.removeOne(child); - [m_nsWindow removeChildWindow:child->m_nsWindow]; -} -bool QCocoaWindow::isNativeWindowTypeInconsistent() -{ - if (!m_nsWindow) - return false; + // Persist modality so we can detect changes later on + m_windowModality = QPlatformWindow::window()->modality(); - const bool isPanel = [m_nsWindow isKindOfClass:[QNSPanel class]]; - const bool usePanel = shouldUseNSPanel(); + applyContentBorderThickness(window); - return isPanel != usePanel; + return window; } void QCocoaWindow::removeMonitor() @@ -1520,7 +1809,7 @@ void QCocoaWindow::removeMonitor() // Returns the current global screen geometry for the nswindow associated with this window. QRect QCocoaWindow::nativeWindowGeometry() const { - if (!m_nsWindow || m_isNSWindowChild) + if (!m_nsWindow || isChildNSWindow()) return geometry(); NSRect rect = [m_nsWindow frame]; @@ -1530,94 +1819,144 @@ QRect QCocoaWindow::nativeWindowGeometry() const return qRect; } -// Returns a pointer to the parent QCocoaWindow for this window, or 0 if there is none. -QCocoaWindow *QCocoaWindow::parentCocoaWindow() const -{ - if (window() && window()->transientParent()) { - return static_cast<QCocoaWindow*>(window()->transientParent()->handle()); - } - return 0; -} +/*! + Applies the given state to the NSWindow, going in/out of minimize/zoomed/fullscreen -// Syncs the NSWindow minimize/maximize/fullscreen state with the current QWindow state -void QCocoaWindow::syncWindowState(Qt::WindowState newState) + When this is called from QWindow::setWindowState(), the QWindow state has not been + updated yet, so window()->windowState() will reflect the previous state that was + reported to QtGui. +*/ +void QCocoaWindow::applyWindowState(Qt::WindowState newState) { + const Qt::WindowState currentState = windowState(); + if (newState == currentState) + return; + if (!m_nsWindow) return; - // if content view width or height is 0 then the window animations will crash so - // do nothing except set the new state - NSRect contentRect = m_view.frame; - if (contentRect.size.width <= 0 || contentRect.size.height <= 0) { + + const NSSize contentSize = m_view.frame.size; + if (contentSize.width <= 0 || contentSize.height <= 0) { + // If content view width or height is 0 then the window animations will crash so + // do nothing. We report the current state back to reflect the failed operation. qWarning("invalid window content view size, check your window geometry"); - m_synchedWindowState = newState; + reportCurrentWindowState(true); return; } - Qt::WindowState predictedState = newState; - if ((m_synchedWindowState & Qt::WindowMaximized) != (newState & Qt::WindowMaximized)) { - const int styleMask = [m_nsWindow styleMask]; - const bool usePerform = styleMask & NSResizableWindowMask; - [m_nsWindow setStyleMask:styleMask | NSResizableWindowMask]; - if (usePerform) - [m_nsWindow performZoom : m_nsWindow]; // toggles - else - [m_nsWindow zoom : m_nsWindow]; // toggles - [m_nsWindow setStyleMask:styleMask]; + if (m_nsWindow.styleMask & NSUtilityWindowMask) { + // Utility panels cannot be fullscreen + qWarning() << window()->type() << "windows can not be made full screen"; + reportCurrentWindowState(true); + return; } - if ((m_synchedWindowState & Qt::WindowMinimized) != (newState & Qt::WindowMinimized)) { - if (newState & Qt::WindowMinimized) { - if ([m_nsWindow styleMask] & NSMiniaturizableWindowMask) - [m_nsWindow performMiniaturize : m_nsWindow]; - else - [m_nsWindow miniaturize : m_nsWindow]; - } else { - [m_nsWindow deminiaturize : m_nsWindow]; - } + const id sender = m_nsWindow; + + // First we need to exit states that can't transition directly to other states + switch (currentState) { + case Qt::WindowMinimized: + [m_nsWindow deminiaturize:sender]; + Q_ASSERT_X(windowState() != Qt::WindowMinimized, "QCocoaWindow", + "[NSWindow deminiaturize:] is synchronous"); + break; + case Qt::WindowFullScreen: { + toggleFullScreen(); + // Exiting fullscreen is not synchronous, so we need to wait for the + // NSWindowDidExitFullScreenNotification before continuing to apply + // the new state. + return; } - - const bool effMax = m_effectivelyMaximized; - if ((m_synchedWindowState & Qt::WindowMaximized) != (newState & Qt::WindowMaximized) || (m_effectivelyMaximized && newState == Qt::WindowNoState)) { - if ((m_synchedWindowState & Qt::WindowFullScreen) == (newState & Qt::WindowFullScreen)) { - [m_nsWindow zoom : m_nsWindow]; // toggles - m_effectivelyMaximized = !effMax; - } else if (!(newState & Qt::WindowMaximized)) { - // it would be nice to change the target geometry that toggleFullScreen will animate toward - // but there is no known way, so the maximized state is not possible at this time - predictedState = static_cast<Qt::WindowState>(static_cast<int>(newState) | Qt::WindowMaximized); - m_effectivelyMaximized = true; - } + default: + Q_FALLTHROUGH(); } - if ((m_synchedWindowState & Qt::WindowFullScreen) != (newState & Qt::WindowFullScreen)) { - if (window()->flags() & Qt::WindowFullscreenButtonHint) { - if (m_effectivelyMaximized && m_synchedWindowState == Qt::WindowFullScreen) - predictedState = Qt::WindowMaximized; - [m_nsWindow toggleFullScreen : m_nsWindow]; - } else { - if (newState & Qt::WindowFullScreen) { - QScreen *screen = window()->screen(); - if (screen) { - if (m_normalGeometry.width() < 0) { - m_oldWindowFlags = m_windowFlags; - window()->setFlags(window()->flags() | Qt::FramelessWindowHint); - m_normalGeometry = nativeWindowGeometry(); - setGeometry(screen->geometry()); - m_presentationOptions = [NSApp presentationOptions]; - [NSApp setPresentationOptions : m_presentationOptions | NSApplicationPresentationAutoHideMenuBar | NSApplicationPresentationAutoHideDock]; - } - } - } else { - window()->setFlags(m_oldWindowFlags); - setGeometry(m_normalGeometry); - m_normalGeometry.setRect(0, 0, -1, -1); - [NSApp setPresentationOptions : m_presentationOptions]; - } + // Then we apply the new state if needed + if (newState == windowState()) + return; + + switch (newState) { + case Qt::WindowFullScreen: + toggleFullScreen(); + break; + case Qt::WindowMaximized: + toggleMaximized(); + break; + case Qt::WindowMinimized: + [m_nsWindow miniaturize:sender]; + break; + case Qt::WindowNoState: + switch (windowState()) { + case Qt::WindowMaximized: + toggleMaximized(); + default: + Q_FALLTHROUGH(); } + break; + default: + Q_UNREACHABLE(); } +} + +void QCocoaWindow::toggleMaximized() +{ + // The NSWindow needs to be resizable, otherwise the window will + // not be possible to zoom back to non-zoomed state. + const bool wasResizable = m_nsWindow.styleMask & NSResizableWindowMask; + m_nsWindow.styleMask |= NSResizableWindowMask; + + const id sender = m_nsWindow; + [m_nsWindow zoom:sender]; + + if (!wasResizable) + m_nsWindow.styleMask &= ~NSResizableWindowMask; +} + +void QCocoaWindow::toggleFullScreen() +{ + // The window needs to have the correct collection behavior for the + // toggleFullScreen call to have an effect. The collection behavior + // will be reset in windowDidEnterFullScreen/windowDidLeaveFullScreen. + m_nsWindow.collectionBehavior |= NSWindowCollectionBehaviorFullScreenPrimary; + + const id sender = m_nsWindow; + [m_nsWindow toggleFullScreen:sender]; +} + +bool QCocoaWindow::isTransitioningToFullScreen() const +{ + NSWindow *window = m_view.window; + return window.styleMask & NSFullScreenWindowMask && !window.qt_fullScreen; +} + +Qt::WindowState QCocoaWindow::windowState() const +{ + // FIXME: Support compound states (Qt::WindowStates) + + NSWindow *window = m_view.window; + if (window.miniaturized) + return Qt::WindowMinimized; + if (window.qt_fullScreen) + return Qt::WindowFullScreen; + if ((window.zoomed && !isTransitioningToFullScreen()) + || (m_lastReportedWindowState == Qt::WindowMaximized && isTransitioningToFullScreen())) + return Qt::WindowMaximized; + + // Note: We do not report Qt::WindowActive, even if isActive() + // is true, as QtGui does not expect this window state to be set. + + return Qt::WindowNoState; +} + +void QCocoaWindow::reportCurrentWindowState(bool unconditionally) +{ + Qt::WindowState currentState = windowState(); + if (!unconditionally && currentState == m_lastReportedWindowState) + return; - // New state is now the current synched state - m_synchedWindowState = predictedState; + QWindowSystemInterface::handleWindowStateChanged<QWindowSystemInterface::SynchronousDelivery>( + window(), currentState, m_lastReportedWindowState); + m_lastReportedWindowState = currentState; } bool QCocoaWindow::setWindowModified(bool modified) @@ -1671,7 +2010,7 @@ void QCocoaWindow::setWindowCursor(NSCursor *cursor) return; // Setting a cursor in a foregin view is not supported. - if (window()->type() == Qt::ForeignWindow) + if (isForeignWindow()) return; [m_windowCursor release]; @@ -1814,15 +2153,13 @@ void QCocoaWindow::exposeWindow() if (!isWindowExposable()) return; - // Update the QWindow's screen property. This property is set - // to QGuiApplication::primaryScreen() at QWindow construciton - // time, and we won't get a NSWindowDidChangeScreenNotification - // on show. The case where the window is initially displayed - // on a non-primary screen needs special handling here. - NSUInteger screenIndex = [[NSScreen screens] indexOfObject:m_nsWindow.screen]; - if (screenIndex != NSNotFound) { - QCocoaScreen *cocoaScreen = QCocoaIntegration::instance()->screenAtIndex(screenIndex); - if (cocoaScreen) + if (window()->isTopLevel()) { + // Update the QWindow's screen property. This property is set + // to QGuiApplication::primaryScreen() at QWindow construciton + // time, and we won't get a NSWindowDidChangeScreenNotification + // on show. The case where the window is initially displayed + // on a non-primary screen needs special handling here. + if (QCocoaScreen *cocoaScreen = QCocoaIntegration::instance()->screenForNSScreen(m_nsWindow.screen)) window()->setScreen(cocoaScreen->screen()); } diff --git a/src/plugins/platforms/cocoa/qmacclipboard.mm b/src/plugins/platforms/cocoa/qmacclipboard.mm index e09bb1e362..f3467fdc73 100644 --- a/src/plugins/platforms/cocoa/qmacclipboard.mm +++ b/src/plugins/platforms/cocoa/qmacclipboard.mm @@ -139,10 +139,22 @@ OSStatus QMacPasteboard::promiseKeeper(PasteboardRef paste, PasteboardItemID id, const long promise_id = (long)id; // Find the kept promise + QList<QMacInternalPasteboardMime*> availableConverters + = QMacInternalPasteboardMime::all(QMacInternalPasteboardMime::MIME_ALL); const QString flavorAsQString = QString::fromCFString(flavor); QMacPasteboard::Promise promise; for (int i = 0; i < qpaste->promises.size(); i++){ QMacPasteboard::Promise tmp = qpaste->promises[i]; + if (!availableConverters.contains(tmp.convertor)) { + // promise.converter is a pointer initialized by the value found + // in QMacInternalPasteboardMime's global list of QMacInternalPasteboardMimes. + // We add pointers to this list in QMacInternalPasteboardMime's ctor; + // we remove these pointers in QMacInternalPasteboardMime's dtor. + // If tmp.converter was not found in this list, we probably have a + // dangling pointer so let's skip it. + continue; + } + if (tmp.itemId == promise_id && tmp.convertor->canConvert(tmp.mime, flavorAsQString)){ promise = tmp; break; diff --git a/src/plugins/platforms/cocoa/qnsview.h b/src/plugins/platforms/cocoa/qnsview.h index f226547b90..a05bd66890 100644 --- a/src/plugins/platforms/cocoa/qnsview.h +++ b/src/plugins/platforms/cocoa/qnsview.h @@ -74,7 +74,6 @@ Q_FORWARD_DECLARE_OBJC_CLASS(QT_MANGLE_NAMESPACE(QNSViewMouseMoveHelper)); QStringList *currentCustomDragTypes; bool m_sendUpAsRightButton; Qt::KeyboardModifiers currentWheelModifiers; - bool m_subscribesForGlobalFrameNotifications; #ifndef QT_NO_OPENGL QCocoaGLContext *m_glContext; bool m_shouldSetGLContextinDrawRect; @@ -89,6 +88,7 @@ Q_FORWARD_DECLARE_OBJC_CLASS(QT_MANGLE_NAMESPACE(QNSViewMouseMoveHelper)); QSet<quint32> m_acceptedKeyDowns; } ++ (QSizeF)defaultViewSize; - (id)init; - (id)initWithCocoaWindow:(QCocoaWindow *)platformWindow; #ifndef QT_NO_OPENGL @@ -101,9 +101,6 @@ Q_FORWARD_DECLARE_OBJC_CLASS(QT_MANGLE_NAMESPACE(QNSViewMouseMoveHelper)); - (void)drawRect:(NSRect)dirtyRect; - (void)drawBackingStoreUsingCoreGraphics:(NSRect)dirtyRect; - (void)updateGeometry; -- (void)notifyWindowStateChanged:(Qt::WindowState)newState; -- (void)windowNotification : (NSNotification *) windowNotification; -- (void)notifyWindowWillZoom:(BOOL)willZoom; - (void)textInputContextKeyboardSelectionDidChangeNotification : (NSNotification *) textInputContextKeyboardSelectionDidChangeNotification; - (void)viewDidHide; - (void)viewDidUnhide; @@ -152,6 +149,11 @@ Q_FORWARD_DECLARE_OBJC_CLASS(QT_MANGLE_NAMESPACE(QNSViewMouseMoveHelper)); @end +@interface QT_MANGLE_NAMESPACE(QNSView) (QtExtras) +@property (nonatomic, readonly) QCocoaWindow *platformWindow; +@property (nonatomic, readonly) BOOL isMenuView; +@end + QT_NAMESPACE_ALIAS_OBJC_CLASS(QNSView); #endif //QNSVIEW_H diff --git a/src/plugins/platforms/cocoa/qnsview.mm b/src/plugins/platforms/cocoa/qnsview.mm index 970ce9e785..967271be9c 100644 --- a/src/plugins/platforms/cocoa/qnsview.mm +++ b/src/plugins/platforms/cocoa/qnsview.mm @@ -140,7 +140,7 @@ static bool _q_dontOverrideCtrlLMB = false; - (id) init { - self = [super initWithFrame : NSMakeRect(0,0, 300,300)]; + self = [super initWithFrame : NSMakeRect(0, 0, [[self class] defaultViewSize].width(), [[self class] defaultViewSize].height())]; if (self) { m_backingStore = 0; m_maskImage = 0; @@ -149,7 +149,6 @@ static bool _q_dontOverrideCtrlLMB = false; m_acceptedMouseDowns = Qt::NoButton; m_frameStrutButtons = Qt::NoButton; m_sendKeyEvent = false; - m_subscribesForGlobalFrameNotifications = false; #ifndef QT_NO_OPENGL m_glContext = 0; m_shouldSetGLContextinDrawRect = false; @@ -181,7 +180,6 @@ static bool _q_dontOverrideCtrlLMB = false; CGImageRelease(m_maskImage); [m_trackingArea release]; m_maskImage = 0; - m_subscribesForGlobalFrameNotifications = false; [m_inputSource release]; [[NSNotificationCenter defaultCenter] removeObserver:self]; [m_mouseMoveHelper release]; @@ -191,6 +189,11 @@ static bool _q_dontOverrideCtrlLMB = false; [super dealloc]; } ++ (QSizeF)defaultViewSize +{ + return QSizeF(300.0, 300.0); +} + - (id)initWithCocoaWindow:(QCocoaWindow *)platformWindow { self = [self init]; @@ -217,11 +220,6 @@ static bool _q_dontOverrideCtrlLMB = false; #endif [self registerDragTypes]; - [self setPostsFrameChangedNotifications : YES]; - [[NSNotificationCenter defaultCenter] addObserver:self - selector:@selector(updateGeometry) - name:NSViewFrameDidChangeNotification - object:self]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(textInputContextKeyboardSelectionDidChangeNotification:) @@ -240,29 +238,14 @@ static bool _q_dontOverrideCtrlLMB = false; //was unable to set view m_shouldSetGLContextinDrawRect = true; } - - if (!m_subscribesForGlobalFrameNotifications) { - // NSOpenGLContext expects us to repaint (or update) the view when - // it changes position on screen. Since this happens unnoticed for - // the view when the parent view moves, we need to register a special - // notification that lets us handle this case: - m_subscribesForGlobalFrameNotifications = true; - [[NSNotificationCenter defaultCenter] addObserver:self - selector:@selector(globalFrameChanged:) - name:NSViewGlobalFrameDidChangeNotification - object:self]; - } } #endif -- (void) globalFrameChanged:(NSNotification*)notification -{ - Q_UNUSED(notification); - m_platformWindow->updateExposedGeometry(); -} - - (void)viewDidMoveToSuperview { + if (m_platformWindow.isNull()) + return; + if (!(m_platformWindow->m_viewIsToBeEmbedded)) return; @@ -281,24 +264,11 @@ static bool _q_dontOverrideCtrlLMB = false; m_backingStore = Q_NULLPTR; } -- (void)viewWillMoveToWindow:(NSWindow *)newWindow -{ - // ### Merge "normal" window code path with this one for 5.1. - if (!(m_platformWindow->window()->type() & Qt::SubWindow)) - return; - - if (newWindow) { - [[NSNotificationCenter defaultCenter] addObserver:self - selector:@selector(windowNotification:) - name:nil // Get all notifications - object:newWindow]; - } - if ([self window]) - [[NSNotificationCenter defaultCenter] removeObserver:self name:nil object:[self window]]; -} - - (QWindow *)topLevelWindow { + if (m_platformWindow.isNull()) + return nullptr; + QWindow *focusWindow = m_platformWindow->window(); // For widgets we need to do a bit of trickery as the window @@ -314,9 +284,12 @@ static bool _q_dontOverrideCtrlLMB = false; - (void)updateGeometry { + if (m_platformWindow.isNull()) + return; + QRect geometry; - if (m_platformWindow->m_isNSWindowChild) { + if (self.window.parentWindow) { return; #if 0 //geometry = QRectF::fromCGRect([self frame]).toRect(); @@ -336,10 +309,10 @@ static bool _q_dontOverrideCtrlLMB = false; geometry = QRect(windowRect.origin.x, qt_mac_flipYCoordinate(windowRect.origin.y + rect.size.height), rect.size.width, rect.size.height); } else if (m_platformWindow->m_viewIsToBeEmbedded) { // embedded child window, use the frame rect ### merge with case below - geometry = QRectF::fromCGRect([self bounds]).toRect(); + geometry = QRectF::fromCGRect(NSRectToCGRect([self bounds])).toRect(); } else { // child window, use the frame rect - geometry = QRectF::fromCGRect([self frame]).toRect(); + geometry = QRectF::fromCGRect(NSRectToCGRect([self frame])).toRect(); } if (m_platformWindow->m_nsWindow && geometry == m_platformWindow->geometry()) @@ -380,79 +353,6 @@ static bool _q_dontOverrideCtrlLMB = false; } } -- (void)notifyWindowStateChanged:(Qt::WindowState)newState -{ - // If the window was maximized, then fullscreen, then tried to go directly to "normal" state, - // this notification will say that it is "normal", but it will still look maximized, and - // if you called performZoom it would actually take it back to "normal". - // So we should say that it is maximized because it actually is. - if (newState == Qt::WindowNoState && m_platformWindow->m_effectivelyMaximized) - newState = Qt::WindowMaximized; - QWindowSystemInterface::handleWindowStateChanged(m_platformWindow->window(), newState); - // We want to read the window state back from the window, - // but the event we just sent may be asynchronous. - QWindowSystemInterface::flushWindowSystemEvents(); - m_platformWindow->setSynchedWindowStateFromWindow(); -} - -- (void)windowNotification : (NSNotification *) windowNotification -{ - //qDebug() << "windowNotification" << QString::fromNSString([windowNotification name]); - - NSString *notificationName = [windowNotification name]; - if (notificationName == NSWindowDidBecomeKeyNotification) { - if (!m_platformWindow->windowIsPopupType() && !m_isMenuView) - QWindowSystemInterface::handleWindowActivated(m_platformWindow->window()); - } else if (notificationName == NSWindowDidResignKeyNotification) { - // key window will be non-nil if another window became key... do not - // set the active window to zero here, the new key window's - // NSWindowDidBecomeKeyNotification hander will change the active window - NSWindow *keyWindow = [NSApp keyWindow]; - if (!keyWindow || keyWindow == windowNotification.object) { - // no new key window, go ahead and set the active window to zero - if (!m_platformWindow->windowIsPopupType() && !m_isMenuView) - QWindowSystemInterface::handleWindowActivated(0); - } - } else if (notificationName == NSWindowDidMiniaturizeNotification - || notificationName == NSWindowDidDeminiaturizeNotification) { - Qt::WindowState newState = notificationName == NSWindowDidMiniaturizeNotification ? - Qt::WindowMinimized : Qt::WindowNoState; - [self notifyWindowStateChanged:newState]; - } else if ([notificationName isEqualToString: @"NSWindowDidOrderOffScreenNotification"]) { - m_platformWindow->obscureWindow(); - } else if ([notificationName isEqualToString: @"NSWindowDidOrderOnScreenAndFinishAnimatingNotification"]) { - m_platformWindow->exposeWindow(); - } else if ([notificationName isEqualToString:NSWindowDidChangeOcclusionStateNotification]) { - // Several unit tests expect paint and/or expose events for windows that are - // sometimes (unpredictably) occluded and some unit tests depend on QWindow::isExposed - - // don't send Expose/Obscure events when running under QTestLib. - static const bool onTestLib = qt_mac_resolveOption(false, "QT_QTESTLIB_RUNNING"); - if (!onTestLib) { - if ((NSUInteger)[self.window occlusionState] & NSWindowOcclusionStateVisible) { - m_platformWindow->exposeWindow(); - } else { - // Send Obscure events on window occlusion to stop animations. - m_platformWindow->obscureWindow(); - } - } - } else if (notificationName == NSWindowDidChangeScreenNotification) { - if (m_platformWindow->window()) { - NSUInteger screenIndex = [[NSScreen screens] indexOfObject:self.window.screen]; - if (screenIndex != NSNotFound) { - QCocoaScreen *cocoaScreen = QCocoaIntegration::instance()->screenAtIndex(screenIndex); - if (cocoaScreen) - QWindowSystemInterface::handleWindowScreenChanged(m_platformWindow->window(), cocoaScreen->screen()); - m_platformWindow->updateExposedGeometry(); - } - } - } else if (notificationName == NSWindowDidEnterFullScreenNotification - || notificationName == NSWindowDidExitFullScreenNotification) { - Qt::WindowState newState = notificationName == NSWindowDidEnterFullScreenNotification ? - Qt::WindowFullScreen : Qt::WindowNoState; - [self notifyWindowStateChanged:newState]; - } -} - - (void)textInputContextKeyboardSelectionDidChangeNotification : (NSNotification *) textInputContextKeyboardSelectionDidChangeNotification { Q_UNUSED(textInputContextKeyboardSelectionDidChangeNotification) @@ -462,14 +362,6 @@ static bool _q_dontOverrideCtrlLMB = false; } } -- (void)notifyWindowWillZoom:(BOOL)willZoom -{ - Qt::WindowState newState = willZoom ? Qt::WindowMaximized : Qt::WindowNoState; - if (!willZoom) - m_platformWindow->m_effectivelyMaximized = false; - [self notifyWindowStateChanged:newState]; -} - - (void)viewDidHide { m_platformWindow->obscureWindow(); @@ -553,7 +445,7 @@ static bool _q_dontOverrideCtrlLMB = false; - (void) drawRect:(NSRect)dirtyRect { - qCDebug(lcQpaCocoaWindow) << "[QNSView drawRect:]" << m_platformWindow->window() << QRectF::fromCGRect(dirtyRect); + qCDebug(lcQpaCocoaWindow) << "[QNSView drawRect:]" << m_platformWindow->window() << QRectF::fromCGRect(NSRectToCGRect(dirtyRect)); #ifndef QT_NO_OPENGL if (m_glContext && m_shouldSetGLContextinDrawRect) { @@ -741,6 +633,9 @@ static bool _q_dontOverrideCtrlLMB = false; - (void)handleMouseEvent:(NSEvent *)theEvent { + if (m_platformWindow.isNull()) + return; + // Tablet events may come in via the mouse event handlers, // check if this is a valid tablet event first. if ([self handleTabletEvent: theEvent]) @@ -755,6 +650,8 @@ static bool _q_dontOverrideCtrlLMB = false; else m_platformWindow->m_forwardWindow.clear(); } + if (targetView->m_platformWindow.isNull()) + return; // Popups implicitly grap mouse events; forward to the active popup if there is one if (QCocoaWindow *popup = QCocoaIntegration::instance()->activePopupWindow()) { @@ -779,6 +676,9 @@ static bool _q_dontOverrideCtrlLMB = false; - (void)handleFrameStrutMouseEvent:(NSEvent *)theEvent { + if (m_platformWindow.isNull()) + return; + // get m_buttons in sync // Don't send frme strut events if we are in the middle of a mouse drag. if (m_buttons != Qt::NoButton) @@ -1058,6 +958,9 @@ static bool _q_dontOverrideCtrlLMB = false; - (void)mouseMovedImpl:(NSEvent *)theEvent { + if (m_platformWindow.isNull()) + return; + if ([self isTransparentForUserInput]) return; @@ -1089,6 +992,9 @@ static bool _q_dontOverrideCtrlLMB = false; - (void)mouseEnteredImpl:(NSEvent *)theEvent { Q_UNUSED(theEvent) + if (m_platformWindow.isNull()) + return; + m_platformWindow->m_windowUnderMouse = true; if ([self isTransparentForUserInput]) @@ -1108,6 +1014,9 @@ static bool _q_dontOverrideCtrlLMB = false; - (void)mouseExitedImpl:(NSEvent *)theEvent { Q_UNUSED(theEvent); + if (m_platformWindow.isNull()) + return; + m_platformWindow->m_windowUnderMouse = false; if ([self isTransparentForUserInput]) @@ -1134,6 +1043,9 @@ Q_GLOBAL_STATIC(QCocoaTabletDeviceDataHash, tabletDeviceDataHash) - (bool)handleTabletEvent: (NSEvent *)theEvent { + if (m_platformWindow.isNull()) + return false; + NSEventType eventType = [theEvent type]; if (eventType != NSTabletPoint && [theEvent subtype] != NSTabletPointEventSubtype) return false; // Not a tablet event. @@ -1292,6 +1204,9 @@ static QTabletEvent::TabletDevice wacomTabletDevice(NSEvent *theEvent) - (bool)shouldSendSingleTouch { + if (m_platformWindow.isNull()) + return true; + // QtWidgets expects single-point touch events, QtDeclarative does not. // Until there is an API we solve this by looking at the window class type. return m_platformWindow->window()->inherits("QWidgetWindow"); @@ -1299,6 +1214,9 @@ static QTabletEvent::TabletDevice wacomTabletDevice(NSEvent *theEvent) - (void)touchesBeganWithEvent:(NSEvent *)event { + if (m_platformWindow.isNull()) + return; + const NSTimeInterval timestamp = [event timestamp]; const QList<QWindowSystemInterface::TouchPoint> points = QCocoaTouch::getCurrentTouchPointList(event, [self shouldSendSingleTouch]); qCDebug(lcQpaTouch) << "touchesBeganWithEvent" << points; @@ -1307,6 +1225,9 @@ static QTabletEvent::TabletDevice wacomTabletDevice(NSEvent *theEvent) - (void)touchesMovedWithEvent:(NSEvent *)event { + if (m_platformWindow.isNull()) + return; + const NSTimeInterval timestamp = [event timestamp]; const QList<QWindowSystemInterface::TouchPoint> points = QCocoaTouch::getCurrentTouchPointList(event, [self shouldSendSingleTouch]); qCDebug(lcQpaTouch) << "touchesMovedWithEvent" << points; @@ -1315,6 +1236,9 @@ static QTabletEvent::TabletDevice wacomTabletDevice(NSEvent *theEvent) - (void)touchesEndedWithEvent:(NSEvent *)event { + if (m_platformWindow.isNull()) + return; + const NSTimeInterval timestamp = [event timestamp]; const QList<QWindowSystemInterface::TouchPoint> points = QCocoaTouch::getCurrentTouchPointList(event, [self shouldSendSingleTouch]); qCDebug(lcQpaTouch) << "touchesEndedWithEvent" << points; @@ -1323,6 +1247,9 @@ static QTabletEvent::TabletDevice wacomTabletDevice(NSEvent *theEvent) - (void)touchesCancelledWithEvent:(NSEvent *)event { + if (m_platformWindow.isNull()) + return; + const NSTimeInterval timestamp = [event timestamp]; const QList<QWindowSystemInterface::TouchPoint> points = QCocoaTouch::getCurrentTouchPointList(event, [self shouldSendSingleTouch]); qCDebug(lcQpaTouch) << "touchesCancelledWithEvent" << points; @@ -1333,7 +1260,7 @@ static QTabletEvent::TabletDevice wacomTabletDevice(NSEvent *theEvent) - (bool)handleGestureAsBeginEnd:(NSEvent *)event { - if (QSysInfo::QSysInfo::MacintoshVersion < QSysInfo::MV_10_11) + if (QOperatingSystemVersion::current() < QOperatingSystemVersion::OSXElCapitan) return false; if ([event phase] == NSEventPhaseBegan) { @@ -1350,6 +1277,9 @@ static QTabletEvent::TabletDevice wacomTabletDevice(NSEvent *theEvent) } - (void)magnifyWithEvent:(NSEvent *)event { + if (m_platformWindow.isNull()) + return; + if ([self handleGestureAsBeginEnd:event]) return; @@ -1364,6 +1294,9 @@ static QTabletEvent::TabletDevice wacomTabletDevice(NSEvent *theEvent) - (void)smartMagnifyWithEvent:(NSEvent *)event { + if (m_platformWindow.isNull()) + return; + static bool zoomIn = true; qCDebug(lcQpaGestures) << "smartMagnifyWithEvent" << zoomIn; const NSTimeInterval timestamp = [event timestamp]; @@ -1377,6 +1310,9 @@ static QTabletEvent::TabletDevice wacomTabletDevice(NSEvent *theEvent) - (void)rotateWithEvent:(NSEvent *)event { + if (m_platformWindow.isNull()) + return; + if ([self handleGestureAsBeginEnd:event]) return; @@ -1390,6 +1326,9 @@ static QTabletEvent::TabletDevice wacomTabletDevice(NSEvent *theEvent) - (void)swipeWithEvent:(NSEvent *)event { + if (m_platformWindow.isNull()) + return; + qCDebug(lcQpaGestures) << "swipeWithEvent" << [event deltaX] << [event deltaY]; const NSTimeInterval timestamp = [event timestamp]; QPointF windowPoint; @@ -1412,6 +1351,9 @@ static QTabletEvent::TabletDevice wacomTabletDevice(NSEvent *theEvent) - (void)beginGestureWithEvent:(NSEvent *)event { + if (m_platformWindow.isNull()) + return; + const NSTimeInterval timestamp = [event timestamp]; QPointF windowPoint; QPointF screenPoint; @@ -1423,6 +1365,9 @@ static QTabletEvent::TabletDevice wacomTabletDevice(NSEvent *theEvent) - (void)endGestureWithEvent:(NSEvent *)event { + if (m_platformWindow.isNull()) + return; + qCDebug(lcQpaGestures) << "endGestureWithEvent"; const NSTimeInterval timestamp = [event timestamp]; QPointF windowPoint; @@ -1436,6 +1381,9 @@ static QTabletEvent::TabletDevice wacomTabletDevice(NSEvent *theEvent) #ifndef QT_NO_WHEELEVENT - (void)scrollWheel:(NSEvent *)theEvent { + if (m_platformWindow.isNull()) + return; + if ([self isTransparentForUserInput]) return [super scrollWheel:theEvent]; @@ -2106,6 +2054,9 @@ static QPoint mapWindowCoordinates(QWindow *source, QWindow *target, QPoint poin // Sends drag update to Qt, return the action - (NSDragOperation)handleDrag:(id <NSDraggingInfo>)sender { + if (m_platformWindow.isNull()) + return NSDragOperationNone; + NSPoint windowPoint = [self convertPoint: [sender draggingLocation] fromView: nil]; QPoint qt_windowPoint(windowPoint.x, windowPoint.y); Qt::DropActions qtAllowed = qt_mac_mapNSDragOperations([sender draggingSourceOperationMask]); @@ -2133,6 +2084,9 @@ static QPoint mapWindowCoordinates(QWindow *source, QWindow *target, QPoint poin - (void)draggingExited:(id <NSDraggingInfo>)sender { + if (m_platformWindow.isNull()) + return; + QWindow *target = findEventTargetWindow(m_platformWindow->window()); if (!target) return; @@ -2147,6 +2101,9 @@ static QPoint mapWindowCoordinates(QWindow *source, QWindow *target, QPoint poin // called on drop, send the drop to Qt and return if it was accepted. - (BOOL)performDragOperation:(id <NSDraggingInfo>)sender { + if (m_platformWindow.isNull()) + return false; + QWindow *target = findEventTargetWindow(m_platformWindow->window()); if (!target) return false; @@ -2177,6 +2134,10 @@ static QPoint mapWindowCoordinates(QWindow *source, QWindow *target, QPoint poin { Q_UNUSED(session); Q_UNUSED(operation); + + if (m_platformWindow.isNull()) + return; + QWindow *target = findEventTargetWindow(m_platformWindow->window()); if (!target) return; @@ -2199,3 +2160,17 @@ static QPoint mapWindowCoordinates(QWindow *source, QWindow *target, QPoint poin } @end + +@implementation QT_MANGLE_NAMESPACE(QNSView) (QtExtras) + +- (QCocoaWindow*)platformWindow +{ + return m_platformWindow.data();; +} + +- (BOOL)isMenuView +{ + return m_isMenuView; +} + +@end diff --git a/src/plugins/platforms/cocoa/qnsviewaccessibility.mm b/src/plugins/platforms/cocoa/qnsviewaccessibility.mm index 73e1f41dd5..645a93edf7 100644 --- a/src/plugins/platforms/cocoa/qnsviewaccessibility.mm +++ b/src/plugins/platforms/cocoa/qnsviewaccessibility.mm @@ -53,6 +53,9 @@ @implementation QNSView (QNSViewAccessibility) - (id)childAccessibleElement { + if (m_platformWindow.isNull()) + return nil; + if (!m_platformWindow->window()->accessibleRoot()) return nil; diff --git a/src/plugins/platforms/cocoa/qnswindowdelegate.h b/src/plugins/platforms/cocoa/qnswindowdelegate.h index f29aa97b68..d2078b5786 100644 --- a/src/plugins/platforms/cocoa/qnswindowdelegate.h +++ b/src/plugins/platforms/cocoa/qnswindowdelegate.h @@ -49,15 +49,9 @@ QCocoaWindow *m_cocoaWindow; } -- (id)initWithQCocoaWindow: (QCocoaWindow *) cocoaWindow; +- (id)initWithQCocoaWindow:(QCocoaWindow *)cocoaWindow; -- (void)windowDidBecomeKey:(NSNotification *)notification; -- (void)windowDidResize:(NSNotification *)notification; -- (void)windowDidMove:(NSNotification *)notification; -- (void)windowWillMove:(NSNotification *)notification; - (BOOL)windowShouldClose:(NSNotification *)notification; -- (BOOL)windowShouldZoom:(NSWindow *)window toFrame:(NSRect)newFrame; -- (void)windowWillClose:(NSNotification *)notification; - (BOOL)window:(NSWindow *)window shouldPopUpDocumentPathMenu:(NSMenu *)menu; - (BOOL)window:(NSWindow *)window shouldDragDocumentWithEvent:(NSEvent *)event from:(NSPoint)dragImageLocation withPasteboard:(NSPasteboard *)pasteboard; diff --git a/src/plugins/platforms/cocoa/qnswindowdelegate.mm b/src/plugins/platforms/cocoa/qnswindowdelegate.mm index 7f988ac963..ce74aa9973 100644 --- a/src/plugins/platforms/cocoa/qnswindowdelegate.mm +++ b/src/plugins/platforms/cocoa/qnswindowdelegate.mm @@ -41,61 +41,17 @@ #include "qcocoahelpers.h" #include <QDebug> +#include <qpa/qplatformscreen.h> #include <qpa/qwindowsysteminterface.h> @implementation QNSWindowDelegate -- (id) initWithQCocoaWindow: (QCocoaWindow *) cocoaWindow +- (id)initWithQCocoaWindow:(QCocoaWindow *)cocoaWindow { - self = [super init]; - - if (self) { + if (self = [super init]) m_cocoaWindow = cocoaWindow; - } - return self; -} - -- (void)windowDidBecomeKey:(NSNotification *)notification -{ - Q_UNUSED(notification); - if (m_cocoaWindow->m_windowUnderMouse) { - QPointF windowPoint; - QPointF screenPoint; - [qnsview_cast(m_cocoaWindow->view()) convertFromScreen:[NSEvent mouseLocation] toWindowPoint:&windowPoint andScreenPoint:&screenPoint]; - QWindowSystemInterface::handleEnterEvent(m_cocoaWindow->m_enterLeaveTargetWindow, windowPoint, screenPoint); - } -} -- (void)windowDidResize:(NSNotification *)notification -{ - Q_UNUSED(notification); - if (m_cocoaWindow) { - m_cocoaWindow->windowDidResize(); - } -} - -- (void)windowDidEndLiveResize:(NSNotification *)notification -{ - Q_UNUSED(notification); - if (m_cocoaWindow) { - m_cocoaWindow->windowDidEndLiveResize(); - } -} - -- (void)windowWillMove:(NSNotification *)notification -{ - Q_UNUSED(notification); - if (m_cocoaWindow) { - m_cocoaWindow->windowWillMove(); - } -} - -- (void)windowDidMove:(NSNotification *)notification -{ - Q_UNUSED(notification); - if (m_cocoaWindow) { - m_cocoaWindow->windowDidMove(); - } + return self; } - (BOOL)windowShouldClose:(NSNotification *)notification @@ -107,20 +63,19 @@ return YES; } - -- (BOOL)windowShouldZoom:(NSWindow *)window toFrame:(NSRect)newFrame +/*! + Overridden to ensure that the zoomed state always results in a maximized + window, which would otherwise not be the case for borderless windows. +*/ +- (NSRect)windowWillUseStandardFrame:(NSWindow *)window defaultFrame:(NSRect)newFrame { Q_UNUSED(newFrame); - if (m_cocoaWindow && m_cocoaWindow->window()->type() != Qt::ForeignWindow) - [qnsview_cast(m_cocoaWindow->view()) notifyWindowWillZoom:![window isZoomed]]; - return YES; -} -- (void)windowWillClose:(NSNotification *)notification -{ - Q_UNUSED(notification); - if (m_cocoaWindow) - m_cocoaWindow->windowWillClose(); + // We explicitly go through the QScreen API here instead of just using + // window.screen.visibleFrame directly, as that ensures we have the same + // behavior for both use-cases/APIs. + Q_ASSERT(window == m_cocoaWindow->nativeWindow()); + return m_cocoaWindow->screen()->availableGeometry().toCGRect(); } - (BOOL)window:(NSWindow *)window shouldPopUpDocumentPathMenu:(NSMenu *)menu diff --git a/src/plugins/platforms/direct2d/qwindowsdirect2dbitmap.cpp b/src/plugins/platforms/direct2d/qwindowsdirect2dbitmap.cpp index b5065ba380..38425f8fa1 100644 --- a/src/plugins/platforms/direct2d/qwindowsdirect2dbitmap.cpp +++ b/src/plugins/platforms/direct2d/qwindowsdirect2dbitmap.cpp @@ -55,8 +55,9 @@ class QWindowsDirect2DBitmapPrivate { public: QWindowsDirect2DBitmapPrivate(ID2D1DeviceContext *dc = 0, ID2D1Bitmap1 *bm = 0) - : bitmap(bm) - , deviceContext(new QWindowsDirect2DDeviceContext(dc)) + : deviceContext(new QWindowsDirect2DDeviceContext(dc)) + , bitmap(bm) + { deviceContext->get()->SetTarget(bm); } @@ -83,13 +84,13 @@ public: UINT32(width), UINT32(height) }; - HRESULT hr = deviceContext->get()->CreateBitmap(size, data, pitch, + HRESULT hr = deviceContext->get()->CreateBitmap(size, data, UINT32(pitch), bitmapProperties(), bitmap.ReleaseAndGetAddressOf()); if (SUCCEEDED(hr)) deviceContext->get()->SetTarget(bitmap.Get()); else - qWarning("%s: Could not create bitmap: %#x", __FUNCTION__, hr); + qWarning("%s: Could not create bitmap: %#lx", __FUNCTION__, hr); return SUCCEEDED(hr); } @@ -107,28 +108,28 @@ public: D2D1_BITMAP_PROPERTIES1 properties = bitmapProperties(); properties.bitmapOptions = D2D1_BITMAP_OPTIONS_CANNOT_DRAW | D2D1_BITMAP_OPTIONS_CPU_READ; - hr = deviceContext->get()->CreateBitmap(size, NULL, NULL, + hr = deviceContext->get()->CreateBitmap(size, NULL, 0, properties, &mappingCopy); if (FAILED(hr)) { - qWarning("%s: Could not create bitmap: %#x", __FUNCTION__, hr); + qWarning("%s: Could not create bitmap: %#lx", __FUNCTION__, hr); return QImage(); } hr = mappingCopy->CopyFromBitmap(NULL, bitmap.Get(), NULL); if (FAILED(hr)) { - qWarning("%s: Could not copy from bitmap: %#x", __FUNCTION__, hr); + qWarning("%s: Could not copy from bitmap: %#lx", __FUNCTION__, hr); return QImage(); } D2D1_MAPPED_RECT mappedRect; hr = mappingCopy->Map(D2D1_MAP_OPTIONS_READ, &mappedRect); if (FAILED(hr)) { - qWarning("%s: Could not map: %#x", __FUNCTION__, hr); + qWarning("%s: Could not map: %#lx", __FUNCTION__, hr); return QImage(); } return QImage(static_cast<const uchar *>(mappedRect.bits), - size.width, size.height, mappedRect.pitch, + int(size.width), int(size.height), int(mappedRect.pitch), QImage::Format_ARGB32_Premultiplied).copy(rect); } @@ -197,7 +198,7 @@ QSize QWindowsDirect2DBitmap::size() const Q_D(const QWindowsDirect2DBitmap); D2D1_SIZE_U size = d->bitmap->GetPixelSize(); - return QSize(size.width, size.height); + return QSize(int(size.width), int(size.height)); } QT_END_NAMESPACE diff --git a/src/plugins/platforms/direct2d/qwindowsdirect2dcontext.cpp b/src/plugins/platforms/direct2d/qwindowsdirect2dcontext.cpp index fb5bb43d17..a5817016e6 100644 --- a/src/plugins/platforms/direct2d/qwindowsdirect2dcontext.cpp +++ b/src/plugins/platforms/direct2d/qwindowsdirect2dcontext.cpp @@ -84,7 +84,7 @@ public: } if (FAILED(hr)) { - qWarning("%s: Could not create Direct3D Device: %#x", __FUNCTION__, hr); + qWarning("%s: Could not create Direct3D Device: %#lx", __FUNCTION__, hr); return false; } @@ -93,7 +93,7 @@ public: hr = d3dDevice.As(&dxgiDevice); if (FAILED(hr)) { - qWarning("%s: DXGI Device interface query failed on D3D Device: %#x", __FUNCTION__, hr); + qWarning("%s: DXGI Device interface query failed on D3D Device: %#lx", __FUNCTION__, hr); return false; } @@ -102,13 +102,13 @@ public: hr = dxgiDevice->GetAdapter(&dxgiAdapter); if (FAILED(hr)) { - qWarning("%s: Failed to probe DXGI Device for parent DXGI Adapter: %#x", __FUNCTION__, hr); + qWarning("%s: Failed to probe DXGI Device for parent DXGI Adapter: %#lx", __FUNCTION__, hr); return false; } hr = dxgiAdapter->GetParent(IID_PPV_ARGS(&dxgiFactory)); if (FAILED(hr)) { - qWarning("%s: Failed to probe DXGI Adapter for parent DXGI Factory: %#x", __FUNCTION__, hr); + qWarning("%s: Failed to probe DXGI Adapter for parent DXGI Factory: %#lx", __FUNCTION__, hr); return false; } @@ -121,26 +121,26 @@ public: hr = D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, options, d2dFactory.GetAddressOf()); if (FAILED(hr)) { - qWarning("%s: Could not create Direct2D Factory: %#x", __FUNCTION__, hr); + qWarning("%s: Could not create Direct2D Factory: %#lx", __FUNCTION__, hr); return false; } hr = d2dFactory->CreateDevice(dxgiDevice.Get(), &d2dDevice); if (FAILED(hr)) { - qWarning("%s: Could not create D2D Device: %#x", __FUNCTION__, hr); + qWarning("%s: Could not create D2D Device: %#lx", __FUNCTION__, hr); return false; } hr = DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory), static_cast<IUnknown **>(&directWriteFactory)); if (FAILED(hr)) { - qWarning("%s: Could not create DirectWrite factory: %#x", __FUNCTION__, hr); + qWarning("%s: Could not create DirectWrite factory: %#lx", __FUNCTION__, hr); return false; } hr = directWriteFactory->GetGdiInterop(&directWriteGdiInterop); if (FAILED(hr)) { - qWarning("%s: Could not create DirectWrite GDI Interop: %#x", __FUNCTION__, hr); + qWarning("%s: Could not create DirectWrite GDI Interop: %#lx", __FUNCTION__, hr); return false; } @@ -161,7 +161,7 @@ QWindowsDirect2DContext::QWindowsDirect2DContext() { } -QWindowsDirect2DContext::~QWindowsDirect2DContext() {} +QWindowsDirect2DContext::~QWindowsDirect2DContext() = default; bool QWindowsDirect2DContext::init() { diff --git a/src/plugins/platforms/direct2d/qwindowsdirect2dcontext.h b/src/plugins/platforms/direct2d/qwindowsdirect2dcontext.h index a3478d2d4e..0d42c65964 100644 --- a/src/plugins/platforms/direct2d/qwindowsdirect2dcontext.h +++ b/src/plugins/platforms/direct2d/qwindowsdirect2dcontext.h @@ -59,7 +59,7 @@ class QWindowsDirect2DContext public: QWindowsDirect2DContext(); - virtual ~QWindowsDirect2DContext(); + ~QWindowsDirect2DContext(); bool init(); diff --git a/src/plugins/platforms/direct2d/qwindowsdirect2ddevicecontext.cpp b/src/plugins/platforms/direct2d/qwindowsdirect2ddevicecontext.cpp index 30238217dd..8a34f6974f 100644 --- a/src/plugins/platforms/direct2d/qwindowsdirect2ddevicecontext.cpp +++ b/src/plugins/platforms/direct2d/qwindowsdirect2ddevicecontext.cpp @@ -51,14 +51,13 @@ class QWindowsDirect2DDeviceContextPrivate { public: QWindowsDirect2DDeviceContextPrivate(ID2D1DeviceContext *dc) : deviceContext(dc) - , refCount(0) { if (!dc) { HRESULT hr = QWindowsDirect2DContext::instance()->d2dDevice()->CreateDeviceContext( D2D1_DEVICE_CONTEXT_OPTIONS_NONE, &deviceContext); if (Q_UNLIKELY(FAILED(hr))) - qFatal("%s: Couldn't create Direct2D Device Context: %#x", __FUNCTION__, hr); + qFatal("%s: Couldn't create Direct2D Device Context: %#lx", __FUNCTION__, hr); } Q_ASSERT(deviceContext); @@ -98,7 +97,7 @@ public: } ComPtr<ID2D1DeviceContext> deviceContext; - int refCount; + int refCount = 0; }; QWindowsDirect2DDeviceContext::QWindowsDirect2DDeviceContext(ID2D1DeviceContext *dc) diff --git a/src/plugins/platforms/direct2d/qwindowsdirect2dintegration.cpp b/src/plugins/platforms/direct2d/qwindowsdirect2dintegration.cpp index da4a4e6ce6..ea51135583 100644 --- a/src/plugins/platforms/direct2d/qwindowsdirect2dintegration.cpp +++ b/src/plugins/platforms/direct2d/qwindowsdirect2dintegration.cpp @@ -76,12 +76,7 @@ public: class Direct2DVersion { private: - Direct2DVersion() - : partOne(0) - , partTwo(0) - , partThree(0) - , partFour(0) - {} + Direct2DVersion() = default; Direct2DVersion(int one, int two, int three, int four) : partOne(one) @@ -108,13 +103,14 @@ public: if (_tcscat_s(filename, bufSize, __TEXT("\\d2d1.dll")) == 0) { DWORD versionInfoSize = GetFileVersionInfoSize(filename, NULL); if (versionInfoSize) { - QVarLengthArray<BYTE> info(versionInfoSize); - if (GetFileVersionInfo(filename, NULL, versionInfoSize, info.data())) { + QVarLengthArray<BYTE> info(static_cast<int>(versionInfoSize)); + if (GetFileVersionInfo(filename, 0, versionInfoSize, info.data())) { UINT size; DWORD *fi; - if (VerQueryValue(info.constData(), __TEXT("\\"), (LPVOID *) &fi, &size) && size) { - VS_FIXEDFILEINFO *verInfo = (VS_FIXEDFILEINFO *) fi; + if (VerQueryValue(info.constData(), __TEXT("\\"), + reinterpret_cast<void **>(&fi), &size) && size) { + const VS_FIXEDFILEINFO *verInfo = reinterpret_cast<const VS_FIXEDFILEINFO *>(fi); return Direct2DVersion(HIWORD(verInfo->dwFileVersionMS), LOWORD(verInfo->dwFileVersionMS), HIWORD(verInfo->dwFileVersionLS), @@ -171,7 +167,10 @@ public: return a - b; } - int partOne, partTwo, partThree, partFour; + int partOne = 0; + int partTwo = 0; + int partThree = 0; + int partFour = 0; }; QWindowsDirect2DIntegration *QWindowsDirect2DIntegration::create(const QStringList ¶mList) diff --git a/src/plugins/platforms/direct2d/qwindowsdirect2dpaintdevice.cpp b/src/plugins/platforms/direct2d/qwindowsdirect2dpaintdevice.cpp index 29b01391e2..3c86168a74 100644 --- a/src/plugins/platforms/direct2d/qwindowsdirect2dpaintdevice.cpp +++ b/src/plugins/platforms/direct2d/qwindowsdirect2dpaintdevice.cpp @@ -93,42 +93,33 @@ int QWindowsDirect2DPaintDevice::metric(QPaintDevice::PaintDeviceMetric metric) switch (metric) { case QPaintDevice::PdmWidth: - return d->bitmap->bitmap()->GetPixelSize().width; - break; + return int(d->bitmap->bitmap()->GetPixelSize().width); case QPaintDevice::PdmHeight: - return d->bitmap->bitmap()->GetPixelSize().height; - break; + return int(d->bitmap->bitmap()->GetPixelSize().height); case QPaintDevice::PdmNumColors: return INT_MAX; - break; case QPaintDevice::PdmDepth: return 32; - break; case QPaintDevice::PdmDpiX: case QPaintDevice::PdmPhysicalDpiX: { FLOAT x, y; QWindowsDirect2DContext::instance()->d2dFactory()->GetDesktopDpi(&x, &y); - return x; + return qRound(x); } - break; case QPaintDevice::PdmDpiY: case QPaintDevice::PdmPhysicalDpiY: { FLOAT x, y; QWindowsDirect2DContext::instance()->d2dFactory()->GetDesktopDpi(&x, &y); - return y; + return qRound(y); } - break; case QPaintDevice::PdmDevicePixelRatio: return 1; - break; case QPaintDevice::PdmDevicePixelRatioScaled: - return 1 * devicePixelRatioFScale(); - break; + return qRound(devicePixelRatioFScale()); case QPaintDevice::PdmWidthMM: case QPaintDevice::PdmHeightMM: - return -1; break; } diff --git a/src/plugins/platforms/direct2d/qwindowsdirect2dpaintengine.cpp b/src/plugins/platforms/direct2d/qwindowsdirect2dpaintengine.cpp index c4ff937a0b..164429ba30 100644 --- a/src/plugins/platforms/direct2d/qwindowsdirect2dpaintengine.cpp +++ b/src/plugins/platforms/direct2d/qwindowsdirect2dpaintengine.cpp @@ -87,7 +87,7 @@ enum { }; //Clipping flags -enum { +enum : unsigned { SimpleSystemClip = 0x1 }; @@ -125,28 +125,30 @@ static inline D2D1_MATRIX_3X2_F transformFromLine(const QLineF &line, qreal penW static void adjustLine(QPointF *p1, QPointF *p2); static bool isLinePositivelySloped(const QPointF &p1, const QPointF &p2); -class Direct2DPathGeometryWriter +static QVector<D2D1_GRADIENT_STOP> qGradientStopsToD2DStops(const QGradientStops &qstops) { -public: - Direct2DPathGeometryWriter() - : m_inFigure(false) - , m_roundCoordinates(false) - , m_adjustPositivelySlopedLines(false) - { - + QVector<D2D1_GRADIENT_STOP> stops(qstops.count()); + for (int i = 0, count = stops.size(); i < count; ++i) { + stops[i].position = FLOAT(qstops.at(i).first); + stops[i].color = to_d2d_color_f(qstops.at(i).second); } + return stops; +} +class Direct2DPathGeometryWriter +{ +public: bool begin() { HRESULT hr = factory()->CreatePathGeometry(&m_geometry); if (FAILED(hr)) { - qWarning("%s: Could not create path geometry: %#x", __FUNCTION__, hr); + qWarning("%s: Could not create path geometry: %#lx", __FUNCTION__, hr); return false; } hr = m_geometry->Open(&m_sink); if (FAILED(hr)) { - qWarning("%s: Could not create geometry sink: %#x", __FUNCTION__, hr); + qWarning("%s: Could not create geometry sink: %#lx", __FUNCTION__, hr); return false; } @@ -239,9 +241,9 @@ private: ComPtr<ID2D1PathGeometry1> m_geometry; ComPtr<ID2D1GeometrySink> m_sink; - bool m_inFigure; - bool m_roundCoordinates; - bool m_adjustPositivelySlopedLines; + bool m_inFigure = false; + bool m_roundCoordinates = false; + bool m_adjustPositivelySlopedLines = false; QPointF m_previousPoint; }; @@ -262,7 +264,6 @@ class QWindowsDirect2DPaintEnginePrivate : public QPaintEngineExPrivate public: QWindowsDirect2DPaintEnginePrivate(QWindowsDirect2DBitmap *bm, QWindowsDirect2DPaintEngine::Flags flags) : bitmap(bm) - , clipFlags(0) , flags(flags) { pen.reset(); @@ -274,7 +275,7 @@ public: QWindowsDirect2DBitmap *bitmap; QImage fallbackImage; - unsigned int clipFlags; + unsigned int clipFlags = 0; QStack<ClipType> pushedClips; QWindowsDirect2DPaintEngine::Flags flags; @@ -348,9 +349,9 @@ public: void updateOpacity(qreal opacity) { if (brush.brush) - brush.brush->SetOpacity(opacity); + brush.brush->SetOpacity(FLOAT(opacity)); if (pen.brush) - pen.brush->SetOpacity(opacity); + pen.brush->SetOpacity(FLOAT(opacity)); } void pushClip(const QVectorPath &path) @@ -459,7 +460,7 @@ public: brush.qbrush = newBrush; if (brush.brush) { - brush.brush->SetOpacity(q->state()->opacity); + brush.brush->SetOpacity(FLOAT(q->state()->opacity)); applyBrushOrigin(currentBrushOrigin); } } @@ -477,8 +478,8 @@ public: brush.brush->GetTransform(&transform); brush.brush->SetTransform(*(D2D1::Matrix3x2F::ReinterpretBaseType(&transform)) - * D2D1::Matrix3x2F::Translation(-currentBrushOrigin.x(), - -currentBrushOrigin.y())); + * D2D1::Matrix3x2F::Translation(FLOAT(-currentBrushOrigin.x()), + FLOAT(-currentBrushOrigin.y()))); } } @@ -489,7 +490,7 @@ public: brush.brush->GetTransform(&transform); brush.brush->SetTransform(*(D2D1::Matrix3x2F::ReinterpretBaseType(&transform)) - * D2D1::Matrix3x2F::Translation(origin.x(), origin.y())); + * D2D1::Matrix3x2F::Translation(FLOAT(origin.x()), FLOAT(origin.y()))); } currentBrushOrigin = origin; @@ -511,7 +512,7 @@ public: if (!pen.brush) return; - pen.brush->SetOpacity(q->state()->opacity); + pen.brush->SetOpacity(FLOAT(q->state()->opacity)); D2D1_STROKE_STYLE_PROPERTIES1 props = {}; @@ -541,8 +542,8 @@ public: break; } - props.miterLimit = newPen.miterLimit() * qreal(2.0); // D2D and Qt miter specs differ - props.dashOffset = newPen.dashOffset(); + props.miterLimit = FLOAT(newPen.miterLimit() * qreal(2.0)); // D2D and Qt miter specs differ + props.dashOffset = FLOAT(newPen.dashOffset()); if (newPen.widthF() == 0) props.transformType = D2D1_STROKE_TRANSFORM_TYPE_HAIRLINE; @@ -577,24 +578,24 @@ public: qreal penWidth = pen.qpen.widthF(); qreal brushWidth = 0; for (int i = 0; i < dashes.size(); i++) { - converted[i] = dashes[i]; + converted[i] = FLOAT(dashes[i]); brushWidth += penWidth * dashes[i]; } - hr = factory()->CreateStrokeStyle(props, converted.constData(), converted.size(), &pen.strokeStyle); + hr = factory()->CreateStrokeStyle(props, converted.constData(), UINT32(converted.size()), &pen.strokeStyle); // Create a combined brush/dash pattern for optimized line drawing QWindowsDirect2DBitmap bitmap; - bitmap.resize(ceil(brushWidth), ceil(penWidth)); + bitmap.resize(int(ceil(brushWidth)), int(ceil(penWidth))); bitmap.deviceContext()->begin(); bitmap.deviceContext()->get()->SetAntialiasMode(antialiasMode()); bitmap.deviceContext()->get()->SetTransform(D2D1::IdentityMatrix()); bitmap.deviceContext()->get()->Clear(); const qreal offsetX = (qreal(bitmap.size().width()) - brushWidth) / 2; const qreal offsetY = qreal(bitmap.size().height()) / 2; - bitmap.deviceContext()->get()->DrawLine(D2D1::Point2F(offsetX, offsetY), - D2D1::Point2F(brushWidth, offsetY), - pen.brush.Get(), penWidth, pen.strokeStyle.Get()); + bitmap.deviceContext()->get()->DrawLine(D2D1::Point2F(FLOAT(offsetX), FLOAT(offsetY)), + D2D1::Point2F(FLOAT(brushWidth), FLOAT(offsetY)), + pen.brush.Get(), FLOAT(penWidth), pen.strokeStyle.Get()); bitmap.deviceContext()->end(); D2D1_BITMAP_BRUSH_PROPERTIES1 bitmapBrushProperties = D2D1::BitmapBrushProperties1( D2D1_EXTEND_MODE_WRAP, D2D1_EXTEND_MODE_CLAMP, D2D1_INTERPOLATION_MODE_LINEAR); @@ -605,7 +606,7 @@ public: } if (FAILED(hr)) - qWarning("%s: Could not create stroke style: %#x", __FUNCTION__, hr); + qWarning("%s: Could not create stroke style: %#lx", __FUNCTION__, hr); } ComPtr<ID2D1Brush> to_d2d_brush(const QBrush &newBrush, bool *needsEmulation) @@ -627,13 +628,13 @@ public: hr = dc()->CreateSolidColorBrush(to_d2d_color_f(newBrush.color()), &solid); if (FAILED(hr)) { - qWarning("%s: Could not create solid color brush: %#x", __FUNCTION__, hr); + qWarning("%s: Could not create solid color brush: %#lx", __FUNCTION__, hr); break; } hr = solid.As(&result); if (FAILED(hr)) - qWarning("%s: Could not convert solid color brush: %#x", __FUNCTION__, hr); + qWarning("%s: Could not convert solid color brush: %#lx", __FUNCTION__, hr); } break; @@ -673,13 +674,13 @@ public: bitmapBrushProperties, &bitmapBrush); if (FAILED(hr)) { - qWarning("%s: Could not create Direct2D bitmap brush for Qt pattern brush: %#x", __FUNCTION__, hr); + qWarning("%s: Could not create Direct2D bitmap brush for Qt pattern brush: %#lx", __FUNCTION__, hr); break; } hr = bitmapBrush.As(&result); if (FAILED(hr)) - qWarning("%s: Could not convert Direct2D bitmap brush for Qt pattern brush: %#x", __FUNCTION__, hr); + qWarning("%s: Could not convert Direct2D bitmap brush for Qt pattern brush: %#lx", __FUNCTION__, hr); } break; @@ -693,33 +694,29 @@ public: D2D1_LINEAR_GRADIENT_BRUSH_PROPERTIES linearGradientBrushProperties; ComPtr<ID2D1GradientStopCollection> gradientStopCollection; - const QGradientStops &qstops = qlinear->stops(); - QVector<D2D1_GRADIENT_STOP> stops(qstops.count()); - linearGradientBrushProperties.startPoint = to_d2d_point_2f(qlinear->start()); linearGradientBrushProperties.endPoint = to_d2d_point_2f(qlinear->finalStop()); - for (int i = 0; i < stops.size(); i++) { - stops[i].position = qstops[i].first; - stops[i].color = to_d2d_color_f(qstops[i].second); - } + const QVector<D2D1_GRADIENT_STOP> stops = qGradientStopsToD2DStops(qlinear->stops()); - hr = dc()->CreateGradientStopCollection(stops.constData(), stops.size(), &gradientStopCollection); + hr = dc()->CreateGradientStopCollection(stops.constData(), + UINT32(stops.size()), + &gradientStopCollection); if (FAILED(hr)) { - qWarning("%s: Could not create gradient stop collection for linear gradient: %#x", __FUNCTION__, hr); + qWarning("%s: Could not create gradient stop collection for linear gradient: %#lx", __FUNCTION__, hr); break; } hr = dc()->CreateLinearGradientBrush(linearGradientBrushProperties, gradientStopCollection.Get(), &linear); if (FAILED(hr)) { - qWarning("%s: Could not create Direct2D linear gradient brush: %#x", __FUNCTION__, hr); + qWarning("%s: Could not create Direct2D linear gradient brush: %#lx", __FUNCTION__, hr); break; } hr = linear.As(&result); if (FAILED(hr)) { - qWarning("%s: Could not convert Direct2D linear gradient brush: %#x", __FUNCTION__, hr); + qWarning("%s: Could not convert Direct2D linear gradient brush: %#lx", __FUNCTION__, hr); break; } } @@ -735,35 +732,29 @@ public: D2D1_RADIAL_GRADIENT_BRUSH_PROPERTIES radialGradientBrushProperties; ComPtr<ID2D1GradientStopCollection> gradientStopCollection; - const QGradientStops &qstops = qradial->stops(); - QVector<D2D1_GRADIENT_STOP> stops(qstops.count()); - radialGradientBrushProperties.center = to_d2d_point_2f(qradial->center()); radialGradientBrushProperties.gradientOriginOffset = to_d2d_point_2f(qradial->focalPoint() - qradial->center()); - radialGradientBrushProperties.radiusX = qradial->radius(); - radialGradientBrushProperties.radiusY = qradial->radius(); + radialGradientBrushProperties.radiusX = FLOAT(qradial->radius()); + radialGradientBrushProperties.radiusY = FLOAT(qradial->radius()); - for (int i = 0; i < stops.size(); i++) { - stops[i].position = qstops[i].first; - stops[i].color = to_d2d_color_f(qstops[i].second); - } + const QVector<D2D1_GRADIENT_STOP> stops = qGradientStopsToD2DStops(qradial->stops()); hr = dc()->CreateGradientStopCollection(stops.constData(), stops.size(), &gradientStopCollection); if (FAILED(hr)) { - qWarning("%s: Could not create gradient stop collection for radial gradient: %#x", __FUNCTION__, hr); + qWarning("%s: Could not create gradient stop collection for radial gradient: %#lx", __FUNCTION__, hr); break; } hr = dc()->CreateRadialGradientBrush(radialGradientBrushProperties, gradientStopCollection.Get(), &radial); if (FAILED(hr)) { - qWarning("%s: Could not create Direct2D radial gradient brush: %#x", __FUNCTION__, hr); + qWarning("%s: Could not create Direct2D radial gradient brush: %#lx", __FUNCTION__, hr); break; } radial.As(&result); if (FAILED(hr)) { - qWarning("%s: Could not convert Direct2D radial gradient brush: %#x", __FUNCTION__, hr); + qWarning("%s: Could not convert Direct2D radial gradient brush: %#lx", __FUNCTION__, hr); break; } } @@ -789,13 +780,13 @@ public: &bitmapBrush); if (FAILED(hr)) { - qWarning("%s: Could not create texture brush: %#x", __FUNCTION__, hr); + qWarning("%s: Could not create texture brush: %#lx", __FUNCTION__, hr); break; } hr = bitmapBrush.As(&result); if (FAILED(hr)) - qWarning("%s: Could not convert texture brush: %#x", __FUNCTION__, hr); + qWarning("%s: Could not convert texture brush: %#lx", __FUNCTION__, hr); } break; } @@ -958,7 +949,8 @@ public: qWarning("%s: Could not convert path to d2d geometry", __FUNCTION__); return; } - dc()->DrawGeometry(geometry.Get(), pen.brush.Get(), pen.qpen.widthF(), pen.strokeStyle.Get()); + dc()->DrawGeometry(geometry.Get(), pen.brush.Get(), + FLOAT(pen.qpen.widthF()), pen.strokeStyle.Get()); return; } @@ -998,7 +990,7 @@ public: dashOffset = pen.dashLength - fmod(lineLength - dashOffset, pen.dashLength); } dc()->DrawLine(to_d2d_point_2f(p1), to_d2d_point_2f(p2), - brush, pen.qpen.widthF(), NULL); + brush, FLOAT(pen.qpen.widthF()), NULL); if (skipJoin) continue; @@ -1013,7 +1005,8 @@ public: writer.lineTo(p1); writer.lineTo(line.pointAt(patchSegment)); writer.close(); - dc()->DrawGeometry(writer.geometry().Get(), pen.brush.Get(), pen.qpen.widthF(), pen.strokeStyle.Get()); + dc()->DrawGeometry(writer.geometry().Get(), pen.brush.Get(), + FLOAT(pen.qpen.widthF()), pen.strokeStyle.Get()); } // Record the start position of the next joint jointStart = line.pointAt(1 - patchSegment); @@ -1025,7 +1018,8 @@ public: writer.lineTo(p2); writer.lineTo(QLineF(p2, QPointF(points[2], points[3])).pointAt(patchSegment)); writer.close(); - dc()->DrawGeometry(writer.geometry().Get(), pen.brush.Get(), pen.qpen.widthF(), pen.strokeStyle.Get()); + dc()->DrawGeometry(writer.geometry().Get(), pen.brush.Get(), + FLOAT(pen.qpen.widthF()), pen.strokeStyle.Get()); } } } @@ -1045,20 +1039,20 @@ public: const QString nameSubstitute = QSettings(QLatin1String(keyC), QSettings::NativeFormat).value(familyName, familyName).toString(); if (nameSubstitute != familyName) { const int nameSubstituteLength = qMin(nameSubstitute.length(), LF_FACESIZE - 1); - memcpy(lf.lfFaceName, nameSubstitute.utf16(), nameSubstituteLength * sizeof(wchar_t)); + memcpy(lf.lfFaceName, nameSubstitute.utf16(), size_t(nameSubstituteLength) * sizeof(wchar_t)); lf.lfFaceName[nameSubstituteLength] = 0; } ComPtr<IDWriteFont> dwriteFont; HRESULT hr = QWindowsDirect2DContext::instance()->dwriteGdiInterop()->CreateFontFromLOGFONT(&lf, &dwriteFont); if (FAILED(hr)) { - qDebug("%s: CreateFontFromLOGFONT failed: %#x", __FUNCTION__, hr); + qDebug("%s: CreateFontFromLOGFONT failed: %#lx", __FUNCTION__, hr); return fontFace; } hr = dwriteFont->CreateFontFace(&fontFace); if (FAILED(hr)) { - qDebug("%s: CreateFontFace failed: %#x", __FUNCTION__, hr); + qDebug("%s: CreateFontFace failed: %#lx", __FUNCTION__, hr); return fontFace; } @@ -1332,7 +1326,8 @@ void QWindowsDirect2DPaintEngine::drawRects(const QRect *rects, int rectCount) d->dc()->FillRectangle(d2d_rect, d->brush.brush.Get()); if (d->pen.brush) - d->dc()->DrawRectangle(d2d_rect, d->pen.brush.Get(), d->pen.qpen.widthF(), d->pen.strokeStyle.Get()); + d->dc()->DrawRectangle(d2d_rect, d->pen.brush.Get(), + FLOAT(d->pen.qpen.widthF()), d->pen.strokeStyle.Get()); } } } @@ -1359,7 +1354,8 @@ void QWindowsDirect2DPaintEngine::drawRects(const QRectF *rects, int rectCount) d->dc()->FillRectangle(d2d_rect, d->brush.brush.Get()); if (d->pen.brush) - d->dc()->DrawRectangle(d2d_rect, d->pen.brush.Get(), d->pen.qpen.widthF(), d->pen.strokeStyle.Get()); + d->dc()->DrawRectangle(d2d_rect, d->pen.brush.Get(), + FLOAT(d->pen.qpen.widthF()), d->pen.strokeStyle.Get()); } } } @@ -1407,7 +1403,9 @@ void QWindowsDirect2DPaintEngine::drawEllipse(const QRectF &r) d->dc()->FillEllipse(ellipse, d->brush.brush.Get()); if (d->pen.brush) - d->dc()->DrawEllipse(ellipse, d->pen.brush.Get(), d->pen.qpen.widthF(), d->pen.strokeStyle.Get()); + d->dc()->DrawEllipse(ellipse, d->pen.brush.Get(), + FLOAT(d->pen.qpen.widthF()), + d->pen.strokeStyle.Get()); } } @@ -1435,7 +1433,9 @@ void QWindowsDirect2DPaintEngine::drawEllipse(const QRect &r) d->dc()->FillEllipse(ellipse, d->brush.brush.Get()); if (d->pen.brush) - d->dc()->DrawEllipse(ellipse, d->pen.brush.Get(), d->pen.qpen.widthF(), d->pen.strokeStyle.Get()); + d->dc()->DrawEllipse(ellipse, d->pen.brush.Get(), + FLOAT(d->pen.qpen.widthF()), + d->pen.strokeStyle.Get()); } } @@ -1490,12 +1490,12 @@ void QWindowsDirect2DPaintEngine::drawPixmap(const QRectF &r, // Good, src bitmap != dst bitmap if (sr.isValid()) d->dc()->DrawBitmap(bitmap->bitmap(), - to_d2d_rect_f(r), state()->opacity, + to_d2d_rect_f(r), FLOAT(state()->opacity), d->interpolationMode(), to_d2d_rect_f(sr)); else d->dc()->DrawBitmap(bitmap->bitmap(), - to_d2d_rect_f(r), state()->opacity, + to_d2d_rect_f(r), FLOAT(state()->opacity), d->interpolationMode()); } else { // Ok, so the source pixmap and destination pixmap is the same. @@ -1504,7 +1504,7 @@ void QWindowsDirect2DPaintEngine::drawPixmap(const QRectF &r, QWindowsDirect2DBitmap intermediate; if (sr.isValid()) { - bool r = intermediate.resize(sr.width(), sr.height()); + bool r = intermediate.resize(int(sr.width()), int(sr.height())); if (!r) { qWarning("%s: Could not resize intermediate bitmap to source rect size", __FUNCTION__); return; @@ -1515,7 +1515,7 @@ void QWindowsDirect2DPaintEngine::drawPixmap(const QRectF &r, bitmap->bitmap(), &d2d_sr); if (FAILED(hr)) { - qWarning("%s: Could not copy source rect area from source bitmap to intermediate bitmap: %#x", __FUNCTION__, hr); + qWarning("%s: Could not copy source rect area from source bitmap to intermediate bitmap: %#lx", __FUNCTION__, hr); return; } } else { @@ -1530,13 +1530,13 @@ void QWindowsDirect2DPaintEngine::drawPixmap(const QRectF &r, bitmap->bitmap(), NULL); if (FAILED(hr)) { - qWarning("%s: Could not copy source bitmap to intermediate bitmap: %#x", __FUNCTION__, hr); + qWarning("%s: Could not copy source bitmap to intermediate bitmap: %#lx", __FUNCTION__, hr); return; } } d->dc()->DrawBitmap(intermediate.bitmap(), - to_d2d_rect_f(r), state()->opacity, + to_d2d_rect_f(r), FLOAT(state()->opacity), d->interpolationMode()); } } @@ -1573,9 +1573,9 @@ void QWindowsDirect2DPaintEngine::drawStaticTextItem(QStaticTextItem *staticText // This looks a little funky because the positions are precalculated glyphAdvances[i] = 0; - glyphOffsets[i].advanceOffset = staticTextItem->glyphPositions[i].x.toReal(); + glyphOffsets[i].advanceOffset = FLOAT(staticTextItem->glyphPositions[i].x.toReal()); // Qt and Direct2D seem to disagree on the direction of the ascender offset... - glyphOffsets[i].ascenderOffset = staticTextItem->glyphPositions[i].y.toReal() * -1; + glyphOffsets[i].ascenderOffset = FLOAT(staticTextItem->glyphPositions[i].y.toReal() * -1); } d->drawGlyphRun(D2D1::Point2F(0, 0), @@ -1618,11 +1618,11 @@ void QWindowsDirect2DPaintEngine::drawTextItem(const QPointF &p, const QTextItem for (int i = 0; i < ti.glyphs.numGlyphs; i++) { glyphIndices[i] = UINT16(ti.glyphs.glyphs[i]); // Imperfect conversion here - glyphAdvances[i] = ti.glyphs.effectiveAdvance(i).toReal(); - glyphOffsets[i].advanceOffset = ti.glyphs.offsets[i].x.toReal(); + glyphAdvances[i] = FLOAT(ti.glyphs.effectiveAdvance(i).toReal()); + glyphOffsets[i].advanceOffset = FLOAT(ti.glyphs.offsets[i].x.toReal()); // XXX Should we negate the y value like for static text items? - glyphOffsets[i].ascenderOffset = ti.glyphs.offsets[i].y.toReal(); + glyphOffsets[i].ascenderOffset = FLOAT(ti.glyphs.offsets[i].y.toReal()); } const bool rtl = (ti.flags & QTextItem::RightToLeft); diff --git a/src/plugins/platforms/direct2d/qwindowsdirect2dplatformpixmap.cpp b/src/plugins/platforms/direct2d/qwindowsdirect2dplatformpixmap.cpp index e7e2fa4ff7..65e056d312 100644 --- a/src/plugins/platforms/direct2d/qwindowsdirect2dplatformpixmap.cpp +++ b/src/plugins/platforms/direct2d/qwindowsdirect2dplatformpixmap.cpp @@ -57,15 +57,12 @@ public: : owns_bitmap(true) , bitmap(new QWindowsDirect2DBitmap) , device(new QWindowsDirect2DPaintDevice(bitmap, QInternal::Pixmap)) - , devicePixelRatio(1.0) {} QWindowsDirect2DPlatformPixmapPrivate(QWindowsDirect2DBitmap *bitmap, QWindowsDirect2DPaintEngine::Flags flags) - : owns_bitmap(false) - , bitmap(bitmap) + : bitmap(bitmap) , device(new QWindowsDirect2DPaintDevice(bitmap, QInternal::Pixmap, flags)) - , devicePixelRatio(1.0) {} ~QWindowsDirect2DPlatformPixmapPrivate() @@ -74,10 +71,10 @@ public: delete bitmap; } - bool owns_bitmap; + bool owns_bitmap = false; QWindowsDirect2DBitmap *bitmap; QScopedPointer<QWindowsDirect2DPaintDevice> device; - qreal devicePixelRatio; + qreal devicePixelRatio = 1.0; }; static int qt_d2dpixmap_serno = 0; diff --git a/src/plugins/platforms/direct2d/qwindowsdirect2dwindow.cpp b/src/plugins/platforms/direct2d/qwindowsdirect2dwindow.cpp index c750b02078..21294cfb15 100644 --- a/src/plugins/platforms/direct2d/qwindowsdirect2dwindow.cpp +++ b/src/plugins/platforms/direct2d/qwindowsdirect2dwindow.cpp @@ -54,7 +54,6 @@ QT_BEGIN_NAMESPACE QWindowsDirect2DWindow::QWindowsDirect2DWindow(QWindow *window, const QWindowsWindowData &data) : QWindowsWindow(window, data) - , m_needsFullFlush(true) , m_directRendering(!(data.flags & Qt::FramelessWindowHint && window->format().hasAlpha())) { if (window->type() == Qt::Desktop) @@ -67,7 +66,7 @@ QWindowsDirect2DWindow::QWindowsDirect2DWindow(QWindow *window, const QWindowsWi D2D1_DEVICE_CONTEXT_OPTIONS_NONE, m_deviceContext.GetAddressOf()); if (FAILED(hr)) - qWarning("%s: Couldn't create Direct2D Device context: %#x", __FUNCTION__, hr); + qWarning("%s: Couldn't create Direct2D Device context: %#lx", __FUNCTION__, hr); } QWindowsDirect2DWindow::~QWindowsDirect2DWindow() @@ -100,12 +99,12 @@ void QWindowsDirect2DWindow::flush(QWindowsDirect2DBitmap *bitmap, const QRegion HRESULT hr = m_swapChain->GetDesc1(&desc); QRect geom = geometry(); - if ((FAILED(hr) || (desc.Width != geom.width()) || (desc.Height != geom.height()))) { + if (FAILED(hr) || (desc.Width != UINT(geom.width()) || (desc.Height != UINT(geom.height())))) { resizeSwapChain(geom.size()); m_swapChain->GetDesc1(&desc); } - size.setWidth(desc.Width); - size.setHeight(desc.Height); + size.setWidth(int(desc.Width)); + size.setHeight(int(desc.Height)); } else { size = geometry().size(); } @@ -175,7 +174,7 @@ void QWindowsDirect2DWindow::present(const QRegion ®ion) UPDATELAYEREDWINDOWINFO info = { sizeof(UPDATELAYEREDWINDOWINFO), NULL, &ptDst, &size, hdc, &ptSrc, 0, &blend, ULW_ALPHA, &dirty }; if (!UpdateLayeredWindowIndirect(handle(), &info)) - qErrnoWarning(GetLastError(), "Failed to update the layered window"); + qErrnoWarning(int(GetLastError()), "Failed to update the layered window"); hr = dxgiSurface->ReleaseDC(NULL); if (FAILED(hr)) @@ -201,7 +200,7 @@ void QWindowsDirect2DWindow::setupSwapChain() m_swapChain.ReleaseAndGetAddressOf()); // [out] IDXGISwapChain1 **ppSwapChain if (FAILED(hr)) - qWarning("%s: Could not create swap chain: %#x", __FUNCTION__, hr); + qWarning("%s: Could not create swap chain: %#lx", __FUNCTION__, hr); m_needsFullFlush = true; } @@ -217,11 +216,11 @@ void QWindowsDirect2DWindow::resizeSwapChain(const QSize &size) return; HRESULT hr = m_swapChain->ResizeBuffers(0, - size.width(), size.height(), + UINT(size.width()), UINT(size.height()), DXGI_FORMAT_UNKNOWN, 0); if (FAILED(hr)) - qWarning("%s: Could not resize swap chain: %#x", __FUNCTION__, hr); + qWarning("%s: Could not resize swap chain: %#lx", __FUNCTION__, hr); } QSharedPointer<QWindowsDirect2DBitmap> QWindowsDirect2DWindow::copyBackBuffer() const @@ -248,13 +247,13 @@ QSharedPointer<QWindowsDirect2DBitmap> QWindowsDirect2DWindow::copyBackBuffer() HRESULT hr = m_deviceContext.Get()->CreateBitmap(size, NULL, 0, properties, ©); if (FAILED(hr)) { - qWarning("%s: Could not create staging bitmap: %#x", __FUNCTION__, hr); + qWarning("%s: Could not create staging bitmap: %#lx", __FUNCTION__, hr); return null_result; } hr = copy.Get()->CopyFromBitmap(NULL, m_bitmap->bitmap(), NULL); if (FAILED(hr)) { - qWarning("%s: Could not copy from bitmap! %#x", __FUNCTION__, hr); + qWarning("%s: Could not copy from bitmap! %#lx", __FUNCTION__, hr); return null_result; } @@ -277,12 +276,12 @@ void QWindowsDirect2DWindow::setupBitmap() if (m_directRendering) { hr = m_swapChain->GetBuffer(0, IID_PPV_ARGS(&backBufferSurface)); if (FAILED(hr)) { - qWarning("%s: Could not query backbuffer for DXGI Surface: %#x", __FUNCTION__, hr); + qWarning("%s: Could not query backbuffer for DXGI Surface: %#lx", __FUNCTION__, hr); return; } } else { const QRect rect = geometry(); - CD3D11_TEXTURE2D_DESC backBufferDesc(DXGI_FORMAT_B8G8R8A8_UNORM, rect.width(), rect.height(), 1, 1); + CD3D11_TEXTURE2D_DESC backBufferDesc(DXGI_FORMAT_B8G8R8A8_UNORM, UINT(rect.width()), UINT(rect.height()), 1, 1); backBufferDesc.BindFlags = D3D11_BIND_RENDER_TARGET; backBufferDesc.MiscFlags = D3D11_RESOURCE_MISC_GDI_COMPATIBLE; ComPtr<ID3D11Texture2D> backBufferTexture; @@ -302,7 +301,7 @@ void QWindowsDirect2DWindow::setupBitmap() ComPtr<ID2D1Bitmap1> backBufferBitmap; hr = m_deviceContext->CreateBitmapFromDxgiSurface(backBufferSurface.Get(), NULL, backBufferBitmap.GetAddressOf()); if (FAILED(hr)) { - qWarning("%s: Could not create Direct2D Bitmap from DXGI Surface: %#x", __FUNCTION__, hr); + qWarning("%s: Could not create Direct2D Bitmap from DXGI Surface: %#lx", __FUNCTION__, hr); return; } diff --git a/src/plugins/platforms/direct2d/qwindowsdirect2dwindow.h b/src/plugins/platforms/direct2d/qwindowsdirect2dwindow.h index 2da0e5f507..156d4660d1 100644 --- a/src/plugins/platforms/direct2d/qwindowsdirect2dwindow.h +++ b/src/plugins/platforms/direct2d/qwindowsdirect2dwindow.h @@ -74,8 +74,8 @@ private: Microsoft::WRL::ComPtr<ID2D1DeviceContext> m_deviceContext; QScopedPointer<QWindowsDirect2DBitmap> m_bitmap; QScopedPointer<QPixmap> m_pixmap; - bool m_needsFullFlush; - bool m_directRendering; + bool m_needsFullFlush = true; + bool m_directRendering = false; }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/eglfs/api/api.pri b/src/plugins/platforms/eglfs/api/api.pri index 0ea65bd1ff..a6d81016b6 100644 --- a/src/plugins/platforms/eglfs/api/api.pri +++ b/src/plugins/platforms/eglfs/api/api.pri @@ -1,21 +1,26 @@ SOURCES += $$PWD/qeglfswindow.cpp \ $$PWD/qeglfsscreen.cpp \ - $$PWD/qeglfscursor.cpp \ $$PWD/qeglfshooks.cpp \ $$PWD/qeglfsdeviceintegration.cpp \ $$PWD/qeglfsintegration.cpp \ - $$PWD/qeglfscontext.cpp \ $$PWD/qeglfsoffscreenwindow.cpp HEADERS += $$PWD/qeglfswindow_p.h \ $$PWD/qeglfsscreen_p.h \ - $$PWD/qeglfscursor_p.h \ $$PWD/qeglfshooks_p.h \ $$PWD/qeglfsdeviceintegration_p.h \ $$PWD/qeglfsintegration_p.h \ - $$PWD/qeglfscontext_p.h \ $$PWD/qeglfsoffscreenwindow_p.h \ $$PWD/qeglfsglobal_p.h +qtConfig(opengl) { + SOURCES += \ + $$PWD/qeglfscursor.cpp \ + $$PWD/qeglfscontext.cpp + HEADERS += \ + $$PWD/qeglfscursor_p.h \ + $$PWD/qeglfscontext_p.h +} + INCLUDEPATH += $$PWD diff --git a/src/plugins/platforms/eglfs/api/qeglfscontext_p.h b/src/plugins/platforms/eglfs/api/qeglfscontext_p.h index ab5bf99c3c..96f7f01381 100644 --- a/src/plugins/platforms/eglfs/api/qeglfscontext_p.h +++ b/src/plugins/platforms/eglfs/api/qeglfscontext_p.h @@ -62,11 +62,11 @@ class Q_EGLFS_EXPORT QEglFSContext : public QEGLPlatformContext public: QEglFSContext(const QSurfaceFormat &format, QPlatformOpenGLContext *share, EGLDisplay display, EGLConfig *config, const QVariant &nativeHandle); - EGLSurface eglSurfaceForPlatformSurface(QPlatformSurface *surface) Q_DECL_OVERRIDE; - EGLSurface createTemporaryOffscreenSurface() Q_DECL_OVERRIDE; - void destroyTemporaryOffscreenSurface(EGLSurface surface) Q_DECL_OVERRIDE; - void runGLChecks() Q_DECL_OVERRIDE; - void swapBuffers(QPlatformSurface *surface) Q_DECL_OVERRIDE; + EGLSurface eglSurfaceForPlatformSurface(QPlatformSurface *surface) override; + EGLSurface createTemporaryOffscreenSurface() override; + void destroyTemporaryOffscreenSurface(EGLSurface surface) override; + void runGLChecks() override; + void swapBuffers(QPlatformSurface *surface) override; private: EGLNativeWindowType m_tempWindow; diff --git a/src/plugins/platforms/eglfs/api/qeglfscursor.cpp b/src/plugins/platforms/eglfs/api/qeglfscursor.cpp index 2b54251a06..19a0e03212 100644 --- a/src/plugins/platforms/eglfs/api/qeglfscursor.cpp +++ b/src/plugins/platforms/eglfs/api/qeglfscursor.cpp @@ -146,8 +146,8 @@ void QEglFSCursor::createShaderPrograms() GraphicsContextData &gfx(m_gfx[QOpenGLContext::currentContext()]); gfx.program = new QOpenGLShaderProgram; - gfx.program->addShaderFromSourceCode(QOpenGLShader::Vertex, textureVertexProgram); - gfx.program->addShaderFromSourceCode(QOpenGLShader::Fragment, textureFragmentProgram); + gfx.program->addCacheableShaderFromSourceCode(QOpenGLShader::Vertex, textureVertexProgram); + gfx.program->addCacheableShaderFromSourceCode(QOpenGLShader::Fragment, textureFragmentProgram); gfx.program->bindAttributeLocation("vertexCoordEntry", 0); gfx.program->bindAttributeLocation("textureCoordEntry", 1); gfx.program->link(); diff --git a/src/plugins/platforms/eglfs/api/qeglfscursor_p.h b/src/plugins/platforms/eglfs/api/qeglfscursor_p.h index bf6dbc8a21..aaeb83cb99 100644 --- a/src/plugins/platforms/eglfs/api/qeglfscursor_p.h +++ b/src/plugins/platforms/eglfs/api/qeglfscursor_p.h @@ -79,7 +79,10 @@ private: QEglFSCursor *m_cursor; }; -class Q_EGLFS_EXPORT QEglFSCursor : public QPlatformCursor, protected QOpenGLFunctions +#if QT_CONFIG(opengl) + +class Q_EGLFS_EXPORT QEglFSCursor : public QPlatformCursor + , protected QOpenGLFunctions { Q_OBJECT public: @@ -87,11 +90,11 @@ public: ~QEglFSCursor(); #ifndef QT_NO_CURSOR - void changeCursor(QCursor *cursor, QWindow *widget) Q_DECL_OVERRIDE; + void changeCursor(QCursor *cursor, QWindow *widget) override; #endif - void pointerEvent(const QMouseEvent &event) Q_DECL_OVERRIDE; - QPoint pos() const Q_DECL_OVERRIDE; - void setPos(const QPoint &pos) Q_DECL_OVERRIDE; + void pointerEvent(const QMouseEvent &event) override; + QPoint pos() const override; + void setPos(const QPoint &pos) override; QRect cursorRect() const; void paintOnScreen(); @@ -100,7 +103,7 @@ public: void updateMouseStatus(); private: - bool event(QEvent *e) Q_DECL_OVERRIDE; + bool event(QEvent *e) override; #ifndef QT_NO_CURSOR bool setCurrentCursor(QCursor *cursor); #endif @@ -153,6 +156,7 @@ private: }; QHash<QOpenGLContext *, GraphicsContextData> m_gfx; }; +#endif // QT_CONFIG(opengl) QT_END_NAMESPACE diff --git a/src/plugins/platforms/eglfs/api/qeglfsdeviceintegration.cpp b/src/plugins/platforms/eglfs/api/qeglfsdeviceintegration.cpp index 3558b929fa..e411ea55e9 100644 --- a/src/plugins/platforms/eglfs/api/qeglfsdeviceintegration.cpp +++ b/src/plugins/platforms/eglfs/api/qeglfsdeviceintegration.cpp @@ -39,7 +39,9 @@ #include "qeglfsdeviceintegration_p.h" #include "qeglfsintegration_p.h" -#include "qeglfscursor_p.h" +#ifndef QT_NO_OPENGL +# include "qeglfscursor_p.h" +#endif #include "qeglfswindow_p.h" #include "qeglfsscreen_p.h" #include "qeglfshooks_p.h" @@ -312,7 +314,12 @@ bool QEglFSDeviceIntegration::hasCapability(QPlatformIntegration::Capability cap QPlatformCursor *QEglFSDeviceIntegration::createCursor(QPlatformScreen *screen) const { +#ifndef QT_NO_OPENGL return new QEglFSCursor(static_cast<QEglFSScreen *>(screen)); +#else + Q_UNUSED(screen); + return nullptr; +#endif } void QEglFSDeviceIntegration::waitForVSync(QPlatformSurface *surface) const @@ -355,7 +362,7 @@ EGLConfig QEglFSDeviceIntegration::chooseConfig(EGLDisplay display, const QSurfa public: Chooser(EGLDisplay display) : QEglConfigChooser(display) { } - bool filterConfig(EGLConfig config) const Q_DECL_OVERRIDE { + bool filterConfig(EGLConfig config) const override { return qt_egl_device_integration()->filterConfig(display(), config) && QEglConfigChooser::filterConfig(config); } diff --git a/src/plugins/platforms/eglfs/api/qeglfsintegration.cpp b/src/plugins/platforms/eglfs/api/qeglfsintegration.cpp index 8cf6660c44..73110dba61 100644 --- a/src/plugins/platforms/eglfs/api/qeglfsintegration.cpp +++ b/src/plugins/platforms/eglfs/api/qeglfsintegration.cpp @@ -42,9 +42,11 @@ #include <qpa/qplatformwindow.h> #include <QtGui/QSurfaceFormat> -#include <QtGui/QOpenGLContext> #include <QtGui/QScreen> -#include <QtGui/QOffscreenSurface> +#ifndef QT_NO_OPENGL +# include <QtGui/QOpenGLContext> +# include <QtGui/QOffscreenSurface> +#endif #include <QtGui/QWindow> #include <QtCore/QLoggingCategory> #include <qpa/qwindowsysteminterface.h> @@ -53,20 +55,26 @@ #include "qeglfsintegration_p.h" #include "qeglfswindow_p.h" #include "qeglfshooks_p.h" -#include "qeglfscontext_p.h" +#ifndef QT_NO_OPENGL +# include "qeglfscontext_p.h" +# include "qeglfscursor_p.h" +#endif #include "qeglfsoffscreenwindow_p.h" -#include "qeglfscursor_p.h" #include <QtEglSupport/private/qeglconvenience_p.h> -#include <QtEglSupport/private/qeglplatformcontext_p.h> -#include <QtEglSupport/private/qeglpbuffer_p.h> +#ifndef QT_NO_OPENGL +# include <QtEglSupport/private/qeglplatformcontext_p.h> +# include <QtEglSupport/private/qeglpbuffer_p.h> +#endif #include <QtFontDatabaseSupport/private/qgenericunixfontdatabase_p.h> #include <QtServiceSupport/private/qgenericunixservices_p.h> #include <QtThemeSupport/private/qgenericunixthemes_p.h> #include <QtEventDispatcherSupport/private/qgenericunixeventdispatcher_p.h> #include <QtFbSupport/private/qfbvthandler_p.h> -#include <QtPlatformCompositorSupport/private/qopenglcompositorbackingstore_p.h> +#ifndef QT_NO_OPENGL +# include <QtPlatformCompositorSupport/private/qopenglcompositorbackingstore_p.h> +#endif #include <QtPlatformHeaders/QEGLNativeContext> @@ -108,9 +116,9 @@ QEglFSIntegration::QEglFSIntegration() initResources(); } -void QEglFSIntegration::addScreen(QPlatformScreen *screen) +void QEglFSIntegration::addScreen(QPlatformScreen *screen, bool isPrimary) { - screenAdded(screen); + screenAdded(screen, isPrimary); } void QEglFSIntegration::removeScreen(QPlatformScreen *screen) @@ -179,11 +187,15 @@ QPlatformTheme *QEglFSIntegration::createPlatformTheme(const QString &name) cons QPlatformBackingStore *QEglFSIntegration::createPlatformBackingStore(QWindow *window) const { +#ifndef QT_NO_OPENGL QOpenGLCompositorBackingStore *bs = new QOpenGLCompositorBackingStore(window); if (!window->handle()) window->create(); static_cast<QEglFSWindow *>(window->handle())->setBackingStore(bs); return bs; +#else + return nullptr; +#endif } QPlatformWindow *QEglFSIntegration::createPlatformWindow(QWindow *window) const @@ -191,11 +203,15 @@ QPlatformWindow *QEglFSIntegration::createPlatformWindow(QWindow *window) const QWindowSystemInterface::flushWindowSystemEvents(QEventLoop::ExcludeUserInputEvents); QEglFSWindow *w = qt_egl_device_integration()->createWindow(window); w->create(); - if (window->type() != Qt::ToolTip) + + // Activate only the window for the primary screen to make input work + if (window->type() != Qt::ToolTip && window->screen() == QGuiApplication::primaryScreen()) w->requestActivateWindow(); + return w; } +#ifndef QT_NO_OPENGL QPlatformOpenGLContext *QEglFSIntegration::createPlatformOpenGLContext(QOpenGLContext *context) const { EGLDisplay dpy = context->screen() ? static_cast<QEglFSScreen *>(context->screen()->handle())->display() : display(); @@ -230,6 +246,7 @@ QPlatformOffscreenSurface *QEglFSIntegration::createPlatformOffscreenSurface(QOf } // Never return null. Multiple QWindows are not supported by this plugin. } +#endif // QT_NO_OPENGL bool QEglFSIntegration::hasCapability(QPlatformIntegration::Capability cap) const { @@ -239,10 +256,16 @@ bool QEglFSIntegration::hasCapability(QPlatformIntegration::Capability cap) cons switch (cap) { case ThreadedPixmaps: return true; +#ifndef QT_NO_OPENGL case OpenGL: return true; case ThreadedOpenGL: return true; - case WindowManagement: return false; case RasterGLSurface: return true; +#else + case OpenGL: return false; + case ThreadedOpenGL: return false; + case RasterGLSurface: return false; +#endif + case WindowManagement: return false; default: return QPlatformIntegration::hasCapability(cap); } } @@ -259,7 +282,8 @@ enum ResourceType { EglConfig, NativeDisplay, XlibDisplay, - WaylandDisplay + WaylandDisplay, + EglSurface }; static int resourceType(const QByteArray &key) @@ -271,7 +295,8 @@ static int resourceType(const QByteArray &key) QByteArrayLiteral("eglconfig"), QByteArrayLiteral("nativedisplay"), QByteArrayLiteral("display"), - QByteArrayLiteral("server_wl_display") + QByteArrayLiteral("server_wl_display"), + QByteArrayLiteral("eglsurface") }; const QByteArray *end = names + sizeof(names) / sizeof(names[0]); const QByteArray *result = std::find(names, end, key); @@ -333,6 +358,10 @@ void *QEglFSIntegration::nativeResourceForWindow(const QByteArray &resource, QWi if (window && window->handle()) result = reinterpret_cast<void*>(static_cast<QEglFSWindow *>(window->handle())->eglWindow()); break; + case EglSurface: + if (window && window->handle()) + result = reinterpret_cast<void*>(static_cast<QEglFSWindow *>(window->handle())->surface()); + break; default: break; } @@ -340,6 +369,7 @@ void *QEglFSIntegration::nativeResourceForWindow(const QByteArray &resource, QWi return result; } +#ifndef QT_NO_OPENGL void *QEglFSIntegration::nativeResourceForContext(const QByteArray &resource, QOpenGLContext *context) { void *result = 0; @@ -374,13 +404,17 @@ static void *eglContextForContext(QOpenGLContext *context) return handle->eglContext(); } +#endif QPlatformNativeInterface::NativeResourceForContextFunction QEglFSIntegration::nativeResourceFunctionForContext(const QByteArray &resource) { +#ifndef QT_NO_OPENGL QByteArray lowerCaseResource = resource.toLower(); if (lowerCaseResource == "get_egl_context") return NativeResourceForContextFunction(eglContextForContext); - +#else + Q_UNUSED(resource); +#endif return 0; } diff --git a/src/plugins/platforms/eglfs/api/qeglfsintegration_p.h b/src/plugins/platforms/eglfs/api/qeglfsintegration_p.h index 1a3a44d441..c288876678 100644 --- a/src/plugins/platforms/eglfs/api/qeglfsintegration_p.h +++ b/src/plugins/platforms/eglfs/api/qeglfsintegration_p.h @@ -69,38 +69,41 @@ class Q_EGLFS_EXPORT QEglFSIntegration : public QPlatformIntegration, public QPl public: QEglFSIntegration(); - void initialize() Q_DECL_OVERRIDE; - void destroy() Q_DECL_OVERRIDE; + void initialize() override; + void destroy() override; EGLDisplay display() const { return m_display; } - QAbstractEventDispatcher *createEventDispatcher() const Q_DECL_OVERRIDE; - QPlatformFontDatabase *fontDatabase() const Q_DECL_OVERRIDE; - QPlatformServices *services() const Q_DECL_OVERRIDE; - QPlatformInputContext *inputContext() const Q_DECL_OVERRIDE { return m_inputContext; } - QPlatformTheme *createPlatformTheme(const QString &name) const Q_DECL_OVERRIDE; + QAbstractEventDispatcher *createEventDispatcher() const override; + QPlatformFontDatabase *fontDatabase() const override; + QPlatformServices *services() const override; + QPlatformInputContext *inputContext() const override { return m_inputContext; } + QPlatformTheme *createPlatformTheme(const QString &name) const override; - QPlatformWindow *createPlatformWindow(QWindow *window) const Q_DECL_OVERRIDE; - QPlatformBackingStore *createPlatformBackingStore(QWindow *window) const Q_DECL_OVERRIDE; - QPlatformOpenGLContext *createPlatformOpenGLContext(QOpenGLContext *context) const Q_DECL_OVERRIDE; - QPlatformOffscreenSurface *createPlatformOffscreenSurface(QOffscreenSurface *surface) const Q_DECL_OVERRIDE; + QPlatformWindow *createPlatformWindow(QWindow *window) const override; + QPlatformBackingStore *createPlatformBackingStore(QWindow *window) const override; +#ifndef QT_NO_OPENGL + QPlatformOpenGLContext *createPlatformOpenGLContext(QOpenGLContext *context) const override; + QPlatformOffscreenSurface *createPlatformOffscreenSurface(QOffscreenSurface *surface) const override; +#endif + bool hasCapability(QPlatformIntegration::Capability cap) const override; - bool hasCapability(QPlatformIntegration::Capability cap) const Q_DECL_OVERRIDE; - - QPlatformNativeInterface *nativeInterface() const Q_DECL_OVERRIDE; + QPlatformNativeInterface *nativeInterface() const override; // QPlatformNativeInterface - void *nativeResourceForIntegration(const QByteArray &resource) Q_DECL_OVERRIDE; - void *nativeResourceForScreen(const QByteArray &resource, QScreen *screen) Q_DECL_OVERRIDE; - void *nativeResourceForWindow(const QByteArray &resource, QWindow *window) Q_DECL_OVERRIDE; - void *nativeResourceForContext(const QByteArray &resource, QOpenGLContext *context) Q_DECL_OVERRIDE; - NativeResourceForContextFunction nativeResourceFunctionForContext(const QByteArray &resource) Q_DECL_OVERRIDE; + void *nativeResourceForIntegration(const QByteArray &resource) override; + void *nativeResourceForScreen(const QByteArray &resource, QScreen *screen) override; + void *nativeResourceForWindow(const QByteArray &resource, QWindow *window) override; +#ifndef QT_NO_OPENGL + void *nativeResourceForContext(const QByteArray &resource, QOpenGLContext *context) override; +#endif + NativeResourceForContextFunction nativeResourceFunctionForContext(const QByteArray &resource) override; - QFunctionPointer platformFunction(const QByteArray &function) const Q_DECL_OVERRIDE; + QFunctionPointer platformFunction(const QByteArray &function) const override; QFbVtHandler *vtHandler() { return m_vtHandler.data(); } - void addScreen(QPlatformScreen *screen); + void addScreen(QPlatformScreen *screen, bool isPrimary = false); void removeScreen(QPlatformScreen *screen); private: diff --git a/src/plugins/platforms/eglfs/api/qeglfsoffscreenwindow_p.h b/src/plugins/platforms/eglfs/api/qeglfsoffscreenwindow_p.h index ec483c64e2..9fdb81efdd 100644 --- a/src/plugins/platforms/eglfs/api/qeglfsoffscreenwindow_p.h +++ b/src/plugins/platforms/eglfs/api/qeglfsoffscreenwindow_p.h @@ -62,8 +62,8 @@ public: QEglFSOffscreenWindow(EGLDisplay display, const QSurfaceFormat &format, QOffscreenSurface *offscreenSurface); ~QEglFSOffscreenWindow(); - QSurfaceFormat format() const Q_DECL_OVERRIDE { return m_format; } - bool isValid() const Q_DECL_OVERRIDE { return m_surface != EGL_NO_SURFACE; } + QSurfaceFormat format() const override { return m_format; } + bool isValid() const override { return m_surface != EGL_NO_SURFACE; } private: QSurfaceFormat m_format; diff --git a/src/plugins/platforms/eglfs/api/qeglfsscreen.cpp b/src/plugins/platforms/eglfs/api/qeglfsscreen.cpp index 5613179041..d5c22b3d37 100644 --- a/src/plugins/platforms/eglfs/api/qeglfsscreen.cpp +++ b/src/plugins/platforms/eglfs/api/qeglfsscreen.cpp @@ -41,7 +41,9 @@ #include <QtGui/qwindow.h> #include <qpa/qwindowsysteminterface.h> #include <qpa/qplatformcursor.h> -#include <QtPlatformCompositorSupport/private/qopenglcompositor_p.h> +#ifndef QT_NO_OPENGL +# include <QtPlatformCompositorSupport/private/qopenglcompositor_p.h> +#endif #include "qeglfsscreen_p.h" #include "qeglfswindow_p.h" @@ -60,7 +62,9 @@ QEglFSScreen::QEglFSScreen(EGLDisplay dpy) QEglFSScreen::~QEglFSScreen() { delete m_cursor; +#ifndef QT_NO_OPENGL QOpenGLCompositor::destroy(); +#endif } QRect QEglFSScreen::geometry() const @@ -145,6 +149,7 @@ void QEglFSScreen::setPrimarySurface(EGLSurface surface) void QEglFSScreen::handleCursorMove(const QPoint &pos) { +#ifndef QT_NO_OPENGL const QOpenGLCompositor *compositor = QOpenGLCompositor::instance(); const QList<QOpenGLCompositorWindow *> windows = compositor->windows(); @@ -178,10 +183,12 @@ void QEglFSScreen::handleCursorMove(const QPoint &pos) if (enter && leave) QWindowSystemInterface::handleEnterLeaveEvent(enter, leave, enter->mapFromGlobal(pos), pos); +#endif } QPixmap QEglFSScreen::grabWindow(WId wid, int x, int y, int width, int height) const { +#ifndef QT_NO_OPENGL QOpenGLCompositor *compositor = QOpenGLCompositor::instance(); const QList<QOpenGLCompositorWindow *> windows = compositor->windows(); Q_ASSERT(!windows.isEmpty()); @@ -224,7 +231,7 @@ QPixmap QEglFSScreen::grabWindow(WId wid, int x, int y, int width, int height) c return QPixmap::fromImage(img).copy(rect); } } - +#endif // QT_NO_OPENGL return QPixmap(); } diff --git a/src/plugins/platforms/eglfs/api/qeglfsscreen_p.h b/src/plugins/platforms/eglfs/api/qeglfsscreen_p.h index 131e619e06..bea7b4c8ef 100644 --- a/src/plugins/platforms/eglfs/api/qeglfsscreen_p.h +++ b/src/plugins/platforms/eglfs/api/qeglfsscreen_p.h @@ -67,22 +67,22 @@ public: QEglFSScreen(EGLDisplay display); ~QEglFSScreen(); - QRect geometry() const Q_DECL_OVERRIDE; + QRect geometry() const override; virtual QRect rawGeometry() const; - int depth() const Q_DECL_OVERRIDE; - QImage::Format format() const Q_DECL_OVERRIDE; + int depth() const override; + QImage::Format format() const override; - QSizeF physicalSize() const Q_DECL_OVERRIDE; - QDpi logicalDpi() const Q_DECL_OVERRIDE; - qreal pixelDensity() const Q_DECL_OVERRIDE; - Qt::ScreenOrientation nativeOrientation() const Q_DECL_OVERRIDE; - Qt::ScreenOrientation orientation() const Q_DECL_OVERRIDE; + QSizeF physicalSize() const override; + QDpi logicalDpi() const override; + qreal pixelDensity() const override; + Qt::ScreenOrientation nativeOrientation() const override; + Qt::ScreenOrientation orientation() const override; - QPlatformCursor *cursor() const Q_DECL_OVERRIDE; + QPlatformCursor *cursor() const override; - qreal refreshRate() const Q_DECL_OVERRIDE; + qreal refreshRate() const override; - QPixmap grabWindow(WId wid, int x, int y, int width, int height) const Q_DECL_OVERRIDE; + QPixmap grabWindow(WId wid, int x, int y, int width, int height) const override; EGLSurface primarySurface() const { return m_surface; } diff --git a/src/plugins/platforms/eglfs/api/qeglfswindow.cpp b/src/plugins/platforms/eglfs/api/qeglfswindow.cpp index 639fc56d2b..9b4732eab4 100644 --- a/src/plugins/platforms/eglfs/api/qeglfswindow.cpp +++ b/src/plugins/platforms/eglfs/api/qeglfswindow.cpp @@ -41,13 +41,17 @@ #include <qpa/qwindowsysteminterface.h> #include <qpa/qplatformintegration.h> #include <private/qguiapplication_p.h> -#include <QtGui/private/qopenglcontext_p.h> -#include <QtGui/QOpenGLContext> +#ifndef QT_NO_OPENGL +# include <QtGui/private/qopenglcontext_p.h> +# include <QtGui/QOpenGLContext> +# include <QtPlatformCompositorSupport/private/qopenglcompositorbackingstore_p.h> +#endif #include <QtEglSupport/private/qeglconvenience_p.h> -#include <QtPlatformCompositorSupport/private/qopenglcompositorbackingstore_p.h> #include "qeglfswindow_p.h" -#include "qeglfscursor_p.h" +#ifndef QT_NO_OPENGL +# include "qeglfscursor_p.h" +#endif #include "qeglfshooks_p.h" #include "qeglfsdeviceintegration_p.h" @@ -55,7 +59,9 @@ QT_BEGIN_NAMESPACE QEglFSWindow::QEglFSWindow(QWindow *w) : QPlatformWindow(w), +#ifndef QT_NO_OPENGL m_backingStore(0), +#endif m_raster(false), m_winId(0), m_surface(EGL_NO_SURFACE), @@ -107,6 +113,7 @@ void QEglFSWindow::create() // raster windows will not have their own native window, surface and context. Instead, // they will be composited onto the root window's surface. QEglFSScreen *screen = this->screen(); +#ifndef QT_NO_OPENGL QOpenGLCompositor *compositor = QOpenGLCompositor::instance(); if (screen->primarySurface() != EGL_NO_SURFACE) { if (Q_UNLIKELY(!isRaster() || !compositor->targetWindow())) { @@ -120,10 +127,10 @@ void QEglFSWindow::create() m_format = compositor->targetWindow()->format(); return; } +#endif // QT_NO_OPENGL m_flags |= HasNativeWindow; setGeometry(QRect()); // will become fullscreen - QWindowSystemInterface::handleExposeEvent(window(), QRect(QPoint(0, 0), geometry().size())); resetSurface(); @@ -135,6 +142,7 @@ void QEglFSWindow::create() screen->setPrimarySurface(m_surface); +#ifndef QT_NO_OPENGL if (isRaster()) { QOpenGLContext *context = new QOpenGLContext(QGuiApplication::instance()); context->setShareContext(qt_gl_global_share_context()); @@ -153,16 +161,18 @@ void QEglFSWindow::create() QCoreApplication::setAttribute(Qt::AA_ShareOpenGLContexts); } } +#endif // QT_NO_OPENGL } void QEglFSWindow::destroy() { QEglFSScreen *screen = this->screen(); if (m_flags.testFlag(HasNativeWindow)) { +#ifndef QT_NO_OPENGL QEglFSCursor *cursor = qobject_cast<QEglFSCursor *>(screen->cursor()); if (cursor) cursor->resetResources(); - +#endif if (screen->primarySurface() == m_surface) screen->setPrimarySurface(EGL_NO_SURFACE); @@ -170,7 +180,9 @@ void QEglFSWindow::destroy() } m_flags = 0; +#ifndef QT_NO_OPENGL QOpenGLCompositor::instance()->removeWindow(this); +#endif } void QEglFSWindow::invalidateSurface() @@ -197,6 +209,7 @@ void QEglFSWindow::resetSurface() void QEglFSWindow::setVisible(bool visible) { +#ifndef QT_NO_OPENGL QOpenGLCompositor *compositor = QOpenGLCompositor::instance(); QList<QOpenGLCompositorWindow *> windows = compositor->windows(); QWindow *wnd = window(); @@ -211,7 +224,9 @@ void QEglFSWindow::setVisible(bool visible) windows.last()->sourceWindow()->requestActivate(); } } - +#else + QWindow *wnd = window(); +#endif QWindowSystemInterface::handleExposeEvent(wnd, QRect(QPoint(0, 0), wnd->geometry().size())); if (visible) @@ -227,11 +242,15 @@ void QEglFSWindow::setGeometry(const QRect &r) else rect = r; + const bool changed = rect != QPlatformWindow::geometry(); QPlatformWindow::setGeometry(rect); // if we corrected the size, trigger a resize event if (rect != r) QWindowSystemInterface::handleGeometryChange(window(), rect, r); + + if (changed) + QWindowSystemInterface::handleExposeEvent(window(), QRect(QPoint(0, 0), rect.size())); } QRect QEglFSWindow::geometry() const @@ -247,9 +266,10 @@ QRect QEglFSWindow::geometry() const void QEglFSWindow::requestActivateWindow() { +#ifndef QT_NO_OPENGL if (window()->type() != Qt::Desktop) QOpenGLCompositor::instance()->moveToTop(this); - +#endif QWindow *wnd = window(); QWindowSystemInterface::handleWindowActivated(wnd); QWindowSystemInterface::handleExposeEvent(wnd, QRect(QPoint(0, 0), wnd->geometry().size())); @@ -259,13 +279,16 @@ void QEglFSWindow::raise() { QWindow *wnd = window(); if (wnd->type() != Qt::Desktop) { +#ifndef QT_NO_OPENGL QOpenGLCompositor::instance()->moveToTop(this); +#endif QWindowSystemInterface::handleExposeEvent(wnd, QRect(QPoint(0, 0), wnd->geometry().size())); } } void QEglFSWindow::lower() { +#ifndef QT_NO_OPENGL QOpenGLCompositor *compositor = QOpenGLCompositor::instance(); QList<QOpenGLCompositorWindow *> windows = compositor->windows(); if (window()->type() != Qt::Desktop && windows.count() > 1) { @@ -276,6 +299,7 @@ void QEglFSWindow::lower() QRect(QPoint(0, 0), windows.last()->sourceWindow()->geometry().size())); } } +#endif } EGLSurface QEglFSWindow::surface() const @@ -303,6 +327,7 @@ bool QEglFSWindow::isRaster() const return m_raster || window()->surfaceType() == QSurface::RasterGLSurface; } +#ifndef QT_NO_OPENGL QWindow *QEglFSWindow::sourceWindow() const { return window(); @@ -321,6 +346,7 @@ void QEglFSWindow::endCompositing() if (m_backingStore) m_backingStore->notifyComposited(); } +#endif WId QEglFSWindow::winId() const { diff --git a/src/plugins/platforms/eglfs/api/qeglfswindow_p.h b/src/plugins/platforms/eglfs/api/qeglfswindow_p.h index 0889f27ae3..6bda262523 100644 --- a/src/plugins/platforms/eglfs/api/qeglfswindow_p.h +++ b/src/plugins/platforms/eglfs/api/qeglfswindow_p.h @@ -56,14 +56,19 @@ #include "qeglfsscreen_p.h" #include <qpa/qplatformwindow.h> -#include <QtPlatformCompositorSupport/private/qopenglcompositor_p.h> +#ifndef QT_NO_OPENGL +# include <QtPlatformCompositorSupport/private/qopenglcompositor_p.h> +#endif QT_BEGIN_NAMESPACE class QOpenGLCompositorBackingStore; class QPlatformTextureList; - +#ifndef QT_NO_OPENGL class Q_EGLFS_EXPORT QEglFSWindow : public QPlatformWindow, public QOpenGLCompositorWindow +#else +class Q_EGLFS_EXPORT QEglFSWindow : public QPlatformWindow +#endif { public: QEglFSWindow(QWindow *w); @@ -72,21 +77,21 @@ public: void create(); void destroy(); - void setGeometry(const QRect &) Q_DECL_OVERRIDE; - QRect geometry() const Q_DECL_OVERRIDE; - void setVisible(bool visible) Q_DECL_OVERRIDE; - void requestActivateWindow() Q_DECL_OVERRIDE; - void raise() Q_DECL_OVERRIDE; - void lower() Q_DECL_OVERRIDE; + void setGeometry(const QRect &) override; + QRect geometry() const override; + void setVisible(bool visible) override; + void requestActivateWindow() override; + void raise() override; + void lower() override; - void propagateSizeHints() Q_DECL_OVERRIDE { } - void setMask(const QRegion &) Q_DECL_OVERRIDE { } - bool setKeyboardGrabEnabled(bool) Q_DECL_OVERRIDE { return false; } - bool setMouseGrabEnabled(bool) Q_DECL_OVERRIDE { return false; } - void setOpacity(qreal) Q_DECL_OVERRIDE; - WId winId() const Q_DECL_OVERRIDE; + void propagateSizeHints() override { } + void setMask(const QRegion &) override { } + bool setKeyboardGrabEnabled(bool) override { return false; } + bool setMouseGrabEnabled(bool) override { return false; } + void setOpacity(qreal) override; + WId winId() const override; - QSurfaceFormat format() const Q_DECL_OVERRIDE; + QSurfaceFormat format() const override; EGLNativeWindowType eglWindow() const; EGLSurface surface() const; @@ -94,19 +99,24 @@ public: bool hasNativeWindow() const { return m_flags.testFlag(HasNativeWindow); } - virtual void invalidateSurface() Q_DECL_OVERRIDE; + void invalidateSurface() override; virtual void resetSurface(); +#ifndef QT_NO_OPENGL QOpenGLCompositorBackingStore *backingStore() { return m_backingStore; } void setBackingStore(QOpenGLCompositorBackingStore *backingStore) { m_backingStore = backingStore; } +#endif bool isRaster() const; - - QWindow *sourceWindow() const Q_DECL_OVERRIDE; - const QPlatformTextureList *textures() const Q_DECL_OVERRIDE; - void endCompositing() Q_DECL_OVERRIDE; +#ifndef QT_NO_OPENGL + QWindow *sourceWindow() const override; + const QPlatformTextureList *textures() const override; + void endCompositing() override; +#endif protected: +#ifndef QT_NO_OPENGL QOpenGLCompositorBackingStore *m_backingStore; +#endif bool m_raster; WId m_winId; diff --git a/src/plugins/platforms/eglfs/deviceintegration/deviceintegration.pro b/src/plugins/platforms/eglfs/deviceintegration/deviceintegration.pro index f936d05927..6d759938b5 100644 --- a/src/plugins/platforms/eglfs/deviceintegration/deviceintegration.pro +++ b/src/plugins/platforms/eglfs/deviceintegration/deviceintegration.pro @@ -9,5 +9,7 @@ qtConfig(eglfs_mali): SUBDIRS += eglfs_mali qtConfig(eglfs_viv): SUBDIRS += eglfs_viv qtConfig(eglfs_viv_wl): SUBDIRS += eglfs_viv_wl +qtConfig(opengl): SUBDIRS += eglfs_emu + eglfs_kms_egldevice.depends = eglfs_kms_support eglfs_kms.depends = eglfs_kms_support diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_brcm/qeglfsbrcmintegration.h b/src/plugins/platforms/eglfs/deviceintegration/eglfs_brcm/qeglfsbrcmintegration.h index 5af628dedd..83bcc487af 100644 --- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_brcm/qeglfsbrcmintegration.h +++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_brcm/qeglfsbrcmintegration.h @@ -47,13 +47,13 @@ QT_BEGIN_NAMESPACE class QEglFSBrcmIntegration : public QEglFSDeviceIntegration { public: - void platformInit() Q_DECL_OVERRIDE; - void platformDestroy() Q_DECL_OVERRIDE; - EGLNativeDisplayType platformDisplay() const Q_DECL_OVERRIDE; - QSize screenSize() const Q_DECL_OVERRIDE; - EGLNativeWindowType createNativeWindow(QPlatformWindow *window, const QSize &size, const QSurfaceFormat &format) Q_DECL_OVERRIDE; - void destroyNativeWindow(EGLNativeWindowType window) Q_DECL_OVERRIDE; - bool hasCapability(QPlatformIntegration::Capability cap) const Q_DECL_OVERRIDE; + void platformInit() override; + void platformDestroy() override; + EGLNativeDisplayType platformDisplay() const override; + QSize screenSize() const override; + EGLNativeWindowType createNativeWindow(QPlatformWindow *window, const QSize &size, const QSurfaceFormat &format) override; + void destroyNativeWindow(EGLNativeWindowType window) override; + bool hasCapability(QPlatformIntegration::Capability cap) const override; }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_brcm/qeglfsbrcmmain.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_brcm/qeglfsbrcmmain.cpp index 80d7631931..fd6665e560 100644 --- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_brcm/qeglfsbrcmmain.cpp +++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_brcm/qeglfsbrcmmain.cpp @@ -48,7 +48,7 @@ class QEglFSBrcmIntegrationPlugin : public QEglFSDeviceIntegrationPlugin Q_PLUGIN_METADATA(IID QEglFSDeviceIntegrationFactoryInterface_iid FILE "eglfs_brcm.json") public: - QEglFSDeviceIntegration *create() Q_DECL_OVERRIDE { return new QEglFSBrcmIntegration; } + QEglFSDeviceIntegration *create() override { return new QEglFSBrcmIntegration; } }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_emu/eglfs_emu.json b/src/plugins/platforms/eglfs/deviceintegration/eglfs_emu/eglfs_emu.json new file mode 100644 index 0000000000..3aa38abd7a --- /dev/null +++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_emu/eglfs_emu.json @@ -0,0 +1,3 @@ +{ + "Keys": [ "eglfs_emu" ] +} diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_emu/eglfs_emu.pro b/src/plugins/platforms/eglfs/deviceintegration/eglfs_emu/eglfs_emu.pro new file mode 100644 index 0000000000..609f04e8a9 --- /dev/null +++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_emu/eglfs_emu.pro @@ -0,0 +1,27 @@ +TARGET = qeglfs-emu-integration + +QT += core-private gui-private eglfsdeviceintegration-private + +INCLUDEPATH += $$PWD/../../api +CONFIG += egl + +# Avoid X11 header collision +DEFINES += QT_EGL_NO_X11 + +OTHER_FILES += $$PWD/eglfs_emu.json + +PLUGIN_TYPE = egldeviceintegrations +PLUGIN_CLASS_NAME = QEglFSEmulatorIntegrationPlugin +load(qt_plugin) + +DISTFILES += \ + eglfs_emu.json + +SOURCES += \ + qeglfsemumain.cpp \ + qeglfsemulatorintegration.cpp \ + qeglfsemulatorscreen.cpp + +HEADERS += \ + qeglfsemulatorintegration.h \ + qeglfsemulatorscreen.h diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_emu/qeglfsemulatorintegration.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_emu/qeglfsemulatorintegration.cpp new file mode 100644 index 0000000000..1abc430da6 --- /dev/null +++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_emu/qeglfsemulatorintegration.cpp @@ -0,0 +1,134 @@ +/**************************************************************************** +** +** 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 "qeglfsemulatorintegration.h" +#include "qeglfsemulatorscreen.h" +#include "private/qeglfsintegration_p.h" + +#include <private/qguiapplication_p.h> +#include <QtEglSupport/private/qeglconvenience_p.h> +#include <QtEglSupport/private/qeglplatformcontext_p.h> + +#include <QtCore/QJsonDocument> +#include <QtCore/QJsonArray> +#include <QtCore/QJsonParseError> + +QT_BEGIN_NAMESPACE + +QEglFSEmulatorIntegration::QEglFSEmulatorIntegration() +{ + // The Qt Emulator provides the ability to render to multiple displays + // In addition to the usual EGL and OpenGLESv2 API's, there are also a + // few additional API's that enable the client (this plugin) to query + // the available screens and their properties, as well as the ability + // to select which screen is the active render target (as this is + // usually handled in a platform specific way and not by EGL itself). + + getDisplays = reinterpret_cast<PFNQGSGETDISPLAYSPROC>(eglGetProcAddress("qgsGetDisplays")); + setDisplay = reinterpret_cast<PFNQGSSETDISPLAYPROC>(eglGetProcAddress("qgsSetDisplay")); +} + +void QEglFSEmulatorIntegration::platformInit() +{ +} + +void QEglFSEmulatorIntegration::platformDestroy() +{ +} + +bool QEglFSEmulatorIntegration::usesDefaultScreen() +{ + // This makes it possible to remotely query and then register our own set of screens + return false; +} + +void QEglFSEmulatorIntegration::screenInit() +{ + QEglFSIntegration *integration = static_cast<QEglFSIntegration *>(QGuiApplicationPrivate::platformIntegration()); + + // Use qgsGetDisplays() call to retrieve the available screens from the Emulator + if (getDisplays) { + QByteArray displaysInfo = getDisplays(); + QJsonParseError error; + QJsonDocument displaysDocument = QJsonDocument::fromJson(displaysInfo, &error); + if (error.error == QJsonParseError::NoError) { + // Document should be an array of screen objects + if (displaysDocument.isArray()){ + QJsonArray screenArray = displaysDocument.array(); + for (auto screenValue : screenArray) { + if (screenValue.isObject()) + integration->addScreen(new QEglFSEmulatorScreen(screenValue.toObject())); + } + } + } else { + qWarning() << "eglfs_emu: Failed to parse display info JSON with error: " << error.errorString(); + } + } else { + qFatal("EGL library doesn't support Emulator extensions"); + } +} + +bool QEglFSEmulatorIntegration::hasCapability(QPlatformIntegration::Capability cap) const +{ + switch (cap) { + case QPlatformIntegration::ThreadedPixmaps: + case QPlatformIntegration::OpenGL: + case QPlatformIntegration::ThreadedOpenGL: + return true; + default: + return false; + } +} + +EGLNativeWindowType QEglFSEmulatorIntegration::createNativeWindow(QPlatformWindow *platformWindow, + const QSize &size, + const QSurfaceFormat &format) +{ + Q_UNUSED(size); + Q_UNUSED(format); + QEglFSEmulatorScreen *screen = static_cast<QEglFSEmulatorScreen *>(platformWindow->screen()); + if (screen && setDisplay) { + // Let the emulator know which screen the window surface is attached to + setDisplay(screen->id()); + } + static QBasicAtomicInt uniqueWindowId = Q_BASIC_ATOMIC_INITIALIZER(0); + return EGLNativeWindowType(qintptr(1 + uniqueWindowId.fetchAndAddRelaxed(1))); +} + +QT_END_NAMESPACE diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_emu/qeglfsemulatorintegration.h b/src/plugins/platforms/eglfs/deviceintegration/eglfs_emu/qeglfsemulatorintegration.h new file mode 100644 index 0000000000..513a5063fb --- /dev/null +++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_emu/qeglfsemulatorintegration.h @@ -0,0 +1,74 @@ +/**************************************************************************** +** +** 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 QEGLFSEMULATORINTEGRATION_H +#define QEGLFSEMULATORINTEGRATION_H + +#include "private/qeglfsdeviceintegration_p.h" + +#include <QtCore/QLoggingCategory> +#include <QtCore/QFunctionPointer> + +typedef const char *(EGLAPIENTRYP PFNQGSGETDISPLAYSPROC) (); +typedef void (EGLAPIENTRYP PFNQGSSETDISPLAYPROC) (uint screen); + +QT_BEGIN_NAMESPACE + +Q_DECLARE_LOGGING_CATEGORY(qLcEglfsEmuDebug) + +class QEglFSEmulatorIntegration : public QEglFSDeviceIntegration +{ +public: + QEglFSEmulatorIntegration(); + + void platformInit() override; + void platformDestroy() override; + bool usesDefaultScreen() override; + void screenInit() override; + bool hasCapability(QPlatformIntegration::Capability cap) const override; + + PFNQGSGETDISPLAYSPROC getDisplays; + PFNQGSSETDISPLAYPROC setDisplay; + + EGLNativeWindowType createNativeWindow(QPlatformWindow *platformWindow, const QSize &size, const QSurfaceFormat &format) override; +}; + +QT_END_NAMESPACE + +#endif // QEGLFSEMULATORINTEGRATION_H diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_emu/qeglfsemulatorscreen.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_emu/qeglfsemulatorscreen.cpp new file mode 100644 index 0000000000..4546088327 --- /dev/null +++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_emu/qeglfsemulatorscreen.cpp @@ -0,0 +1,178 @@ +/**************************************************************************** +** +** 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 "qeglfsemulatorscreen.h" + +QT_BEGIN_NAMESPACE + +QEglFSEmulatorScreen::QEglFSEmulatorScreen(const QJsonObject &screenDescription) + : QEglFSScreen(eglGetDisplay(EGL_DEFAULT_DISPLAY)) + , m_id(0) +{ + initFromJsonObject(screenDescription); +} + +QRect QEglFSEmulatorScreen::geometry() const +{ + return m_geometry; +} + +QRect QEglFSEmulatorScreen::rawGeometry() const +{ + return QRect(QPoint(0, 0), m_geometry.size()); +} + +int QEglFSEmulatorScreen::depth() const +{ + return m_depth; +} + +QImage::Format QEglFSEmulatorScreen::format() const +{ + return m_format; +} + +QSizeF QEglFSEmulatorScreen::physicalSize() const +{ + return m_physicalSize; +} + +QDpi QEglFSEmulatorScreen::logicalDpi() const +{ + const QSizeF ps = m_physicalSize; + const QSize s = m_geometry.size(); + + if (!ps.isEmpty() && !s.isEmpty()) + return QDpi(25.4 * s.width() / ps.width(), + 25.4 * s.height() / ps.height()); + else + return QDpi(100, 100); +} + +qreal QEglFSEmulatorScreen::pixelDensity() const +{ + return m_pixelDensity; +} + +qreal QEglFSEmulatorScreen::refreshRate() const +{ + return m_refreshRate; +} + +Qt::ScreenOrientation QEglFSEmulatorScreen::nativeOrientation() const +{ + return m_nativeOrientation; +} + +Qt::ScreenOrientation QEglFSEmulatorScreen::orientation() const +{ + return m_orientation; +} + +uint QEglFSEmulatorScreen::id() const +{ + return m_id; +} + +void QEglFSEmulatorScreen::initFromJsonObject(const QJsonObject &description) +{ + QJsonValue value; + + value = description.value(QLatin1String("id")); + if (!value.isUndefined() && value.isDouble()) + m_id = value.toInt(); + + value = description.value(QLatin1String("description")); + if (!value.isUndefined() && value.isString()) + m_description = value.toString(); + + value = description.value(QLatin1String("geometry")); + if (!value.isUndefined() && value.isObject()) { + QJsonObject geometryObject = value.toObject(); + value = geometryObject.value(QLatin1String("x")); + if (!value.isUndefined() && value.isDouble()) + m_geometry.setX(value.toInt()); + value = geometryObject.value(QLatin1String("y")); + if (!value.isUndefined() && value.isDouble()) + m_geometry.setY(value.toInt()); + value = geometryObject.value(QLatin1String("width")); + if (!value.isUndefined() && value.isDouble()) + m_geometry.setWidth(value.toInt()); + value = geometryObject.value(QLatin1String("height")); + if (!value.isUndefined() && value.isDouble()) + m_geometry.setHeight(value.toInt()); + } + + value = description.value(QLatin1String("depth")); + if (!value.isUndefined() && value.isDouble()) + m_depth = value.toInt(); + + value = description.value(QLatin1String("format")); + if (!value.isUndefined() && value.isDouble()) + m_format = static_cast<QImage::Format>(value.toInt()); + + value = description.value(QLatin1String("physicalSize")); + if (!value.isUndefined() && value.isObject()) { + QJsonObject physicalSizeObject = value.toObject(); + value = physicalSizeObject.value(QLatin1String("width")); + if (!value.isUndefined() && value.isDouble()) + m_physicalSize.setWidth(value.toInt()); + value = physicalSizeObject.value(QLatin1String("height")); + if (!value.isUndefined() && value.isDouble()) + m_physicalSize.setHeight(value.toInt()); + } + + value = description.value(QLatin1String("pixelDensity")); + if (!value.isUndefined() && value.isDouble()) + m_pixelDensity = value.toDouble(); + + value = description.value(QLatin1String("refreshRate")); + if (!value.isUndefined() && value.isDouble()) + m_refreshRate = value.toDouble(); + + value = description.value(QLatin1String("nativeOrientation")); + if (!value.isUndefined() && value.isDouble()) + m_nativeOrientation = static_cast<Qt::ScreenOrientation>(value.toInt()); + + value = description.value(QLatin1String("orientation")); + if (!value.isUndefined() && value.isDouble()) + m_orientation = static_cast<Qt::ScreenOrientation>(value.toInt()); +} + +QT_END_NAMESPACE diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_emu/qeglfsemulatorscreen.h b/src/plugins/platforms/eglfs/deviceintegration/eglfs_emu/qeglfsemulatorscreen.h new file mode 100644 index 0000000000..3e5113c9c2 --- /dev/null +++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_emu/qeglfsemulatorscreen.h @@ -0,0 +1,85 @@ +/**************************************************************************** +** +** 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 QEGLFSEMULATORSCREEN_H +#define QEGLFSEMULATORSCREEN_H + +#include <QtCore/QJsonObject> + +#include "qeglfsemulatorintegration.h" +#include "private/qeglfsscreen_p.h" + +QT_BEGIN_NAMESPACE + +class QEglFSEmulatorScreen : public QEglFSScreen +{ +public: + QEglFSEmulatorScreen(const QJsonObject &screenDescription); + + QRect geometry() const override; + QRect rawGeometry() const override; + int depth() const override; + QImage::Format format() const override; + QSizeF physicalSize() const override; + QDpi logicalDpi() const override; + qreal pixelDensity() const override; + qreal refreshRate() const override; + Qt::ScreenOrientation nativeOrientation() const override; + Qt::ScreenOrientation orientation() const override; + + uint id() const; + +private: + void initFromJsonObject(const QJsonObject &description); + + QString m_description; + QRect m_geometry; + int m_depth; + QImage::Format m_format; + QSizeF m_physicalSize; + float m_pixelDensity; + float m_refreshRate; + Qt::ScreenOrientation m_nativeOrientation; + Qt::ScreenOrientation m_orientation; + uint m_id; +}; + +QT_END_NAMESPACE + +#endif // QEGLFSEMULATORSCREEN_H diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_emu/qeglfsemumain.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_emu/qeglfsemumain.cpp new file mode 100644 index 0000000000..a9923851ef --- /dev/null +++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_emu/qeglfsemumain.cpp @@ -0,0 +1,56 @@ +/**************************************************************************** +** +** 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 "private/qeglfsdeviceintegration_p.h" +#include "qeglfsemulatorintegration.h" + +QT_BEGIN_NAMESPACE + +class QEglFSEmulatorIntegrationPlugin : public QEglFSDeviceIntegrationPlugin +{ + Q_OBJECT + Q_PLUGIN_METADATA(IID QEglFSDeviceIntegrationFactoryInterface_iid FILE "eglfs_emu.json") + +public: + QEglFSDeviceIntegration *create() override { return new QEglFSEmulatorIntegration; } +}; + +QT_END_NAMESPACE + +#include "qeglfsemumain.moc" diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/eglfs_kms.pro b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/eglfs_kms.pro index 255db824b7..e522c0ee1b 100644 --- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/eglfs_kms.pro +++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/eglfs_kms.pro @@ -4,7 +4,7 @@ PLUGIN_TYPE = egldeviceintegrations PLUGIN_CLASS_NAME = QEglFSKmsGbmIntegrationPlugin load(qt_plugin) -QT += core-private gui-private eglfsdeviceintegration-private eglfs_kms_support-private +QT += core-private gui-private eglfsdeviceintegration-private eglfs_kms_support-private kms_support-private INCLUDEPATH += $$PWD/../../api $$PWD/../eglfs_kms_support diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmcursor.h b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmcursor.h index de13a058cf..c96dd585d3 100644 --- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmcursor.h +++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmcursor.h @@ -76,12 +76,12 @@ public: ~QEglFSKmsGbmCursor(); // input methods - void pointerEvent(const QMouseEvent & event) Q_DECL_OVERRIDE; + void pointerEvent(const QMouseEvent & event) override; #ifndef QT_NO_CURSOR - void changeCursor(QCursor * windowCursor, QWindow * window) Q_DECL_OVERRIDE; + void changeCursor(QCursor * windowCursor, QWindow * window) override; #endif - QPoint pos() const Q_DECL_OVERRIDE; - void setPos(const QPoint &pos) Q_DECL_OVERRIDE; + QPoint pos() const override; + void setPos(const QPoint &pos) override; void updateMouseStatus(); diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmdevice.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmdevice.cpp index 3a220ec942..2040d6bc0e 100644 --- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmdevice.cpp +++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmdevice.cpp @@ -46,7 +46,6 @@ #include <QtCore/QLoggingCategory> #include <QtCore/private/qcore_unix_p.h> -#include <QtGui/private/qguiapplication_p.h> #define ARRAY_LENGTH(a) (sizeof (a) / sizeof (a)[0]) @@ -65,8 +64,8 @@ void QEglFSKmsGbmDevice::pageFlipHandler(int fd, unsigned int sequence, unsigned screen->flipFinished(); } -QEglFSKmsGbmDevice::QEglFSKmsGbmDevice(QEglFSKmsIntegration *integration, const QString &path) - : QEglFSKmsDevice(integration, path) +QEglFSKmsGbmDevice::QEglFSKmsGbmDevice(QKmsScreenConfig *screenConfig, const QString &path) + : QEglFSKmsDevice(screenConfig, path) , m_gbm_device(Q_NULLPTR) , m_globalCursor(Q_NULLPTR) { @@ -77,7 +76,6 @@ bool QEglFSKmsGbmDevice::open() Q_ASSERT(fd() == -1); Q_ASSERT(m_gbm_device == Q_NULLPTR); - qCDebug(qLcEglfsKmsDebug) << "Opening device" << devicePath(); int fd = qt_safe_open(devicePath().toLocal8Bit().constData(), O_RDWR | O_CLOEXEC); if (fd == -1) { qErrnoWarning("Could not open DRM device %s", qPrintable(devicePath())); @@ -101,6 +99,8 @@ bool QEglFSKmsGbmDevice::open() void QEglFSKmsGbmDevice::close() { + // Note: screens are gone at this stage. + if (m_gbm_device) { gbm_device_destroy(m_gbm_device); m_gbm_device = Q_NULLPTR; @@ -110,15 +110,11 @@ void QEglFSKmsGbmDevice::close() qt_safe_close(fd()); setFd(-1); } - - if (m_globalCursor) - m_globalCursor->deleteLater(); - m_globalCursor = Q_NULLPTR; } -EGLNativeDisplayType QEglFSKmsGbmDevice::nativeDisplay() const +void *QEglFSKmsGbmDevice::nativeDisplay() const { - return reinterpret_cast<EGLNativeDisplayType>(m_gbm_device); + return m_gbm_device; } gbm_device * QEglFSKmsGbmDevice::gbmDevice() const @@ -131,6 +127,17 @@ QPlatformCursor *QEglFSKmsGbmDevice::globalCursor() const return m_globalCursor; } +// Cannot do this from close(), it may be too late. +// Call this from the last screen dtor instead. +void QEglFSKmsGbmDevice::destroyGlobalCursor() +{ + if (m_globalCursor) { + qCDebug(qLcEglfsKmsDebug, "Destroying global GBM mouse cursor"); + delete m_globalCursor; + m_globalCursor = Q_NULLPTR; + } +} + void QEglFSKmsGbmDevice::handleDrmEvent() { drmEventContext drmEvent = { @@ -142,14 +149,13 @@ void QEglFSKmsGbmDevice::handleDrmEvent() drmHandleEvent(fd(), &drmEvent); } -QEglFSKmsScreen *QEglFSKmsGbmDevice::createScreen(QEglFSKmsIntegration *integration, QEglFSKmsDevice *device, QEglFSKmsOutput output) +QPlatformScreen *QEglFSKmsGbmDevice::createScreen(const QKmsOutput &output) { - static bool firstScreen = true; - QEglFSKmsGbmScreen *screen = new QEglFSKmsGbmScreen(integration, device, output); + QEglFSKmsGbmScreen *screen = new QEglFSKmsGbmScreen(this, output); - if (firstScreen && integration->hwCursor()) { + if (!m_globalCursor && screenConfig()->hwCursor()) { + qCDebug(qLcEglfsKmsDebug, "Creating new global GBM mouse cursor"); m_globalCursor = new QEglFSKmsGbmCursor(screen); - firstScreen = false; } return screen; diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmdevice.h b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmdevice.h index 7c0af84422..08ca28d48e 100644 --- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmdevice.h +++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmdevice.h @@ -43,7 +43,7 @@ #define QEGLFSKMSGBMDEVICE_H #include "qeglfskmsgbmcursor.h" -#include "qeglfskmsdevice.h" +#include <qeglfskmsdevice.h> #include <gbm.h> @@ -54,21 +54,20 @@ class QEglFSKmsScreen; class QEglFSKmsGbmDevice: public QEglFSKmsDevice { public: - QEglFSKmsGbmDevice(QEglFSKmsIntegration *integration, const QString &path); + QEglFSKmsGbmDevice(QKmsScreenConfig *screenConfig, const QString &path); - bool open() Q_DECL_OVERRIDE; - void close() Q_DECL_OVERRIDE; + bool open() override; + void close() override; - EGLNativeDisplayType nativeDisplay() const Q_DECL_OVERRIDE; + void *nativeDisplay() const override; gbm_device *gbmDevice() const; QPlatformCursor *globalCursor() const; + void destroyGlobalCursor(); void handleDrmEvent(); - virtual QEglFSKmsScreen *createScreen(QEglFSKmsIntegration *integration, - QEglFSKmsDevice *device, - QEglFSKmsOutput output) Q_DECL_OVERRIDE; + QPlatformScreen *createScreen(const QKmsOutput &output) override; private: Q_DISABLE_COPY(QEglFSKmsGbmDevice) diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmintegration.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmintegration.cpp index 38419a55c8..b6cdcf92b6 100644 --- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmintegration.cpp +++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmintegration.cpp @@ -63,8 +63,9 @@ QT_BEGIN_NAMESPACE QMutex QEglFSKmsGbmScreen::m_waitForFlipMutex; QEglFSKmsGbmIntegration::QEglFSKmsGbmIntegration() - : QEglFSKmsIntegration() -{} +{ + qCDebug(qLcEglfsKmsDebug, "New DRM/KMS via GBM integration created"); +} EGLNativeWindowType QEglFSKmsGbmIntegration::createNativeWindow(QPlatformWindow *platformWindow, const QSize &size, @@ -104,10 +105,13 @@ void QEglFSKmsGbmIntegration::destroyNativeWindow(EGLNativeWindowType window) QPlatformCursor *QEglFSKmsGbmIntegration::createCursor(QPlatformScreen *screen) const { - if (hwCursor()) - return Q_NULLPTR; - else +#if QT_CONFIG(opengl) + if (!screenConfig()->hwCursor()) { + qCDebug(qLcEglfsKmsDebug, "Using plain OpenGL mouse cursor"); return new QEglFSCursor(screen); + } +#endif + return nullptr; } void QEglFSKmsGbmIntegration::presentBuffer(QPlatformSurface *surface) @@ -118,13 +122,12 @@ void QEglFSKmsGbmIntegration::presentBuffer(QPlatformSurface *surface) screen->flip(); } -QEglFSKmsDevice *QEglFSKmsGbmIntegration::createDevice(const QString &devicePath) +QKmsDevice *QEglFSKmsGbmIntegration::createDevice() { - QString path = devicePath; - if (!devicePath.isEmpty()) { - qCDebug(qLcEglfsKmsDebug) << "Using DRM device" << path << "specified in config file"; + QString path = screenConfig()->devicePath(); + if (!path.isEmpty()) { + qCDebug(qLcEglfsKmsDebug) << "GBM: Using DRM device" << path << "specified in config file"; } else { - QDeviceDiscovery *d = QDeviceDiscovery::create(QDeviceDiscovery::Device_VideoMask); const QStringList devices = d->scanConnectedDevices(); qCDebug(qLcEglfsKmsDebug) << "Found the following video devices:" << devices; @@ -137,7 +140,7 @@ QEglFSKmsDevice *QEglFSKmsGbmIntegration::createDevice(const QString &devicePath qCDebug(qLcEglfsKmsDebug) << "Using" << path; } - return new QEglFSKmsGbmDevice(this, path); + return new QEglFSKmsGbmDevice(screenConfig(), path); } QT_END_NAMESPACE diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmintegration.h b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmintegration.h index 727571d3e3..38f132d72e 100644 --- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmintegration.h +++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmintegration.h @@ -57,15 +57,15 @@ public: EGLNativeWindowType createNativeWindow(QPlatformWindow *platformWindow, const QSize &size, - const QSurfaceFormat &format) Q_DECL_OVERRIDE; - EGLNativeWindowType createNativeOffscreenWindow(const QSurfaceFormat &format) Q_DECL_OVERRIDE; - void destroyNativeWindow(EGLNativeWindowType window) Q_DECL_OVERRIDE; + const QSurfaceFormat &format) override; + EGLNativeWindowType createNativeOffscreenWindow(const QSurfaceFormat &format) override; + void destroyNativeWindow(EGLNativeWindowType window) override; - QPlatformCursor *createCursor(QPlatformScreen *screen) const Q_DECL_OVERRIDE; - void presentBuffer(QPlatformSurface *surface) Q_DECL_OVERRIDE; + QPlatformCursor *createCursor(QPlatformScreen *screen) const override; + void presentBuffer(QPlatformSurface *surface) override; protected: - QEglFSKmsDevice *createDevice(const QString &devicePath) Q_DECL_OVERRIDE; + QKmsDevice *createDevice() override; private: }; diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmmain.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmmain.cpp index f34e4859c6..945c8b4255 100644 --- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmmain.cpp +++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmmain.cpp @@ -49,7 +49,7 @@ class QEglFSKmsGbmIntegrationPlugin : public QEglFSDeviceIntegrationPlugin Q_PLUGIN_METADATA(IID QEglFSDeviceIntegrationFactoryInterface_iid FILE "eglfs_kms.json") public: - QEglFSDeviceIntegration *create() Q_DECL_OVERRIDE { return new QEglFSKmsGbmIntegration; } + QEglFSDeviceIntegration *create() override { return new QEglFSKmsGbmIntegration; } }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmscreen.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmscreen.cpp index d4df0dc66e..87fb3146c7 100644 --- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmscreen.cpp +++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmscreen.cpp @@ -49,6 +49,8 @@ #include <QtGui/private/qguiapplication_p.h> #include <QtFbSupport/private/qfbvthandler_p.h> +#include <errno.h> + QT_BEGIN_NAMESPACE Q_DECLARE_LOGGING_CATEGORY(qLcEglfsKmsDebug) @@ -92,10 +94,8 @@ QEglFSKmsGbmScreen::FrameBuffer *QEglFSKmsGbmScreen::framebufferForBufferObject( return fb.take(); } -QEglFSKmsGbmScreen::QEglFSKmsGbmScreen(QEglFSKmsIntegration *integration, - QEglFSKmsDevice *device, - QEglFSKmsOutput output) - : QEglFSKmsScreen(integration, device, output) +QEglFSKmsGbmScreen::QEglFSKmsGbmScreen(QKmsDevice *device, const QKmsOutput &output) + : QEglFSKmsScreen(device, output) , m_gbm_surface(Q_NULLPTR) , m_gbm_bo_current(Q_NULLPTR) , m_gbm_bo_next(Q_NULLPTR) @@ -105,12 +105,17 @@ QEglFSKmsGbmScreen::QEglFSKmsGbmScreen(QEglFSKmsIntegration *integration, QEglFSKmsGbmScreen::~QEglFSKmsGbmScreen() { + const int remainingScreenCount = qGuiApp->screens().count(); + qCDebug(qLcEglfsKmsDebug, "Screen dtor. Remaining screens: %d", remainingScreenCount); + if (!remainingScreenCount && !device()->screenConfig()->separateScreens()) + static_cast<QEglFSKmsGbmDevice *>(device())->destroyGlobalCursor(); } QPlatformCursor *QEglFSKmsGbmScreen::cursor() const { - if (integration()->hwCursor()) { - if (!integration()->separateScreens()) + QKmsScreenConfig *config = device()->screenConfig(); + if (config->hwCursor()) { + if (!config->separateScreens()) return static_cast<QEglFSKmsGbmDevice *>(device())->globalCursor(); if (m_cursor.isNull()) { @@ -181,7 +186,7 @@ void QEglFSKmsGbmScreen::flip() FrameBuffer *fb = framebufferForBufferObject(m_gbm_bo_next); - QEglFSKmsOutput &op(output()); + QKmsOutput &op(output()); const int fd = device()->fd(); const uint32_t w = op.modes[op.mode].hdisplay; const uint32_t h = op.modes[op.mode].vdisplay; diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmscreen.h b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmscreen.h index d7ad348291..341cc95bbe 100644 --- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmscreen.h +++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmscreen.h @@ -54,20 +54,18 @@ class QEglFSKmsGbmCursor; class QEglFSKmsGbmScreen : public QEglFSKmsScreen { public: - QEglFSKmsGbmScreen(QEglFSKmsIntegration *integration, - QEglFSKmsDevice *device, - QEglFSKmsOutput output); + QEglFSKmsGbmScreen(QKmsDevice *device, const QKmsOutput &output); ~QEglFSKmsGbmScreen(); - QPlatformCursor *cursor() const Q_DECL_OVERRIDE; + QPlatformCursor *cursor() const override; gbm_surface *surface() const { return m_gbm_surface; } gbm_surface *createSurface(); void destroySurface(); - void waitForFlip() Q_DECL_OVERRIDE; - void flip() Q_DECL_OVERRIDE; - void flipFinished() Q_DECL_OVERRIDE; + void waitForFlip() override; + void flip() override; + void flipFinished() override; private: gbm_surface *m_gbm_surface; diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/eglfs_kms_egldevice.pro b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/eglfs_kms_egldevice.pro index a625021aba..a2dc9c4a50 100644 --- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/eglfs_kms_egldevice.pro +++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/eglfs_kms_egldevice.pro @@ -1,6 +1,6 @@ TARGET = qeglfs-kms-egldevice-integration -QT += core-private gui-private eglfsdeviceintegration-private eglfs_kms_support-private +QT += core-private gui-private eglfsdeviceintegration-private eglfs_kms_support-private kms_support-private INCLUDEPATH += $$PWD/../../api $$PWD/../eglfs_kms_support diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldevice.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldevice.cpp index 60989e2bd0..0a66a897a1 100644 --- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldevice.cpp +++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldevice.cpp @@ -40,14 +40,16 @@ #include "qeglfskmsegldevice.h" #include "qeglfskmsegldevicescreen.h" #include "qeglfskmsegldeviceintegration.h" +#include "private/qeglfsintegration_p.h" #include "private/qeglfscursor_p.h" #include <QtCore/private/qcore_unix_p.h> QT_BEGIN_NAMESPACE -QEglFSKmsEglDevice::QEglFSKmsEglDevice(QEglFSKmsIntegration *integration, const QString &path) - : QEglFSKmsDevice(integration, path), +QEglFSKmsEglDevice::QEglFSKmsEglDevice(QEglFSKmsEglDeviceIntegration *devInt, QKmsScreenConfig *screenConfig, const QString &path) + : QEglFSKmsDevice(screenConfig, path), + m_devInt(devInt), m_globalCursor(nullptr) { } @@ -56,11 +58,9 @@ bool QEglFSKmsEglDevice::open() { Q_ASSERT(fd() == -1); - qCDebug(qLcEglfsKmsDebug, "Opening DRM device %s", qPrintable(devicePath())); - int fd = drmOpen(devicePath().toLocal8Bit().constData(), Q_NULLPTR); if (Q_UNLIKELY(fd < 0)) - qFatal("Could not open DRM device"); + qFatal("Could not open DRM (NV) device"); setFd(fd); @@ -69,29 +69,28 @@ bool QEglFSKmsEglDevice::open() void QEglFSKmsEglDevice::close() { - qCDebug(qLcEglfsKmsDebug, "Closing DRM device"); + // Note: screens are gone at this stage. if (qt_safe_close(fd()) == -1) - qErrnoWarning("Could not close DRM device"); + qErrnoWarning("Could not close DRM (NV) device"); setFd(-1); } EGLNativeDisplayType QEglFSKmsEglDevice::nativeDisplay() const { - return reinterpret_cast<EGLNativeDisplayType>(static_cast<QEglFSKmsEglDeviceIntegration *>(m_integration)->eglDevice()); + return reinterpret_cast<EGLNativeDisplayType>(m_devInt->eglDevice()); } -QEglFSKmsScreen *QEglFSKmsEglDevice::createScreen(QEglFSKmsIntegration *integration, QEglFSKmsDevice *device, - QEglFSKmsOutput output) +QPlatformScreen *QEglFSKmsEglDevice::createScreen(const QKmsOutput &output) { - QEglFSKmsScreen *screen = new QEglFSKmsEglDeviceScreen(integration, device, output); - - if (!m_globalCursor && !integration->separateScreens()) { + QEglFSKmsScreen *screen = new QEglFSKmsEglDeviceScreen(this, output); +#if QT_CONFIG(opengl) + if (!m_globalCursor && !screenConfig()->separateScreens()) { qCDebug(qLcEglfsKmsDebug, "Creating new global mouse cursor"); m_globalCursor = new QEglFSCursor(screen); } - +#endif return screen; } diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldevice.h b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldevice.h index 8c8f79f70c..8d469879ab 100644 --- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldevice.h +++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldevice.h @@ -45,25 +45,25 @@ QT_BEGIN_NAMESPACE class QPlatformCursor; +class QEglFSKmsEglDeviceIntegration; class QEglFSKmsEglDevice: public QEglFSKmsDevice { public: - QEglFSKmsEglDevice(QEglFSKmsIntegration *integration, const QString &path); + QEglFSKmsEglDevice(QEglFSKmsEglDeviceIntegration *devInt, QKmsScreenConfig *screenConfig, const QString &path); - virtual bool open() Q_DECL_OVERRIDE; - virtual void close() Q_DECL_OVERRIDE; + bool open() override; + void close() override; - virtual EGLNativeDisplayType nativeDisplay() const Q_DECL_OVERRIDE; + void *nativeDisplay() const override; - virtual QEglFSKmsScreen *createScreen(QEglFSKmsIntegration *integration, - QEglFSKmsDevice *device, - QEglFSKmsOutput output) Q_DECL_OVERRIDE; + QPlatformScreen *createScreen(const QKmsOutput &output) override; QPlatformCursor *globalCursor() { return m_globalCursor; } void destroyGlobalCursor(); private: + QEglFSKmsEglDeviceIntegration *m_devInt; QPlatformCursor *m_globalCursor; }; diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldeviceintegration.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldeviceintegration.cpp index cf1de71831..43bdb77a18 100644 --- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldeviceintegration.cpp +++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldeviceintegration.cpp @@ -50,8 +50,7 @@ QT_BEGIN_NAMESPACE QEglFSKmsEglDeviceIntegration::QEglFSKmsEglDeviceIntegration() - : QEglFSKmsIntegration() - , m_egl_device(EGL_NO_DEVICE_EXT) + : m_egl_device(EGL_NO_DEVICE_EXT) , m_funcs(Q_NULLPTR) { qCDebug(qLcEglfsKmsDebug, "New DRM/KMS on EGLDevice integration created"); @@ -101,30 +100,30 @@ bool QEglFSKmsEglDeviceIntegration::supportsPBuffers() const return true; } -class QEglJetsonTK1Window : public QEglFSWindow +class QEglFSKmsEglDeviceWindow : public QEglFSWindow { public: - QEglJetsonTK1Window(QWindow *w, const QEglFSKmsEglDeviceIntegration *integration) + QEglFSKmsEglDeviceWindow(QWindow *w, const QEglFSKmsEglDeviceIntegration *integration) : QEglFSWindow(w) , m_integration(integration) , m_egl_stream(EGL_NO_STREAM_KHR) { } - void invalidateSurface() Q_DECL_OVERRIDE; - void resetSurface() Q_DECL_OVERRIDE; + void invalidateSurface() override; + void resetSurface() override; const QEglFSKmsEglDeviceIntegration *m_integration; EGLStreamKHR m_egl_stream; EGLint m_latency; }; -void QEglJetsonTK1Window::invalidateSurface() +void QEglFSKmsEglDeviceWindow::invalidateSurface() { QEglFSWindow::invalidateSurface(); m_integration->m_funcs->destroy_stream(screen()->display(), m_egl_stream); } -void QEglJetsonTK1Window::resetSurface() +void QEglFSKmsEglDeviceWindow::resetSurface() { qCDebug(qLcEglfsKmsDebug, "Creating stream"); @@ -173,7 +172,7 @@ void QEglJetsonTK1Window::resetSurface() QEglFSKmsEglDeviceScreen *cur_screen = static_cast<QEglFSKmsEglDeviceScreen *>(screen()); Q_ASSERT(cur_screen); - QEglFSKmsOutput &output(cur_screen->output()); + QKmsOutput &output(cur_screen->output()); const uint32_t wantedId = !output.wants_plane ? output.crtc_id : output.plane_id; qCDebug(qLcEglfsKmsDebug, "Searching for id: %d", wantedId); @@ -235,7 +234,7 @@ void QEglJetsonTK1Window::resetSurface() QEglFSWindow *QEglFSKmsEglDeviceIntegration::createWindow(QWindow *window) const { - QEglJetsonTK1Window *eglWindow = new QEglJetsonTK1Window(window, this); + QEglFSKmsEglDeviceWindow *eglWindow = new QEglFSKmsEglDeviceWindow(window, this); m_funcs->initialize(eglWindow->screen()->display()); if (Q_UNLIKELY(!(m_funcs->has_egl_output_base && m_funcs->has_egl_output_drm && m_funcs->has_egl_stream && @@ -245,10 +244,8 @@ QEglFSWindow *QEglFSKmsEglDeviceIntegration::createWindow(QWindow *window) const return eglWindow; } -QEglFSKmsDevice *QEglFSKmsEglDeviceIntegration::createDevice(const QString &devicePath) +QKmsDevice *QEglFSKmsEglDeviceIntegration::createDevice() { - Q_UNUSED(devicePath) - if (Q_UNLIKELY(!query_egl_device())) qFatal("Could not set up EGL device!"); @@ -256,7 +253,7 @@ QEglFSKmsDevice *QEglFSKmsEglDeviceIntegration::createDevice(const QString &devi if (Q_UNLIKELY(!deviceName)) qFatal("Failed to query device name from EGLDevice"); - return new QEglFSKmsEglDevice(this, deviceName); + return new QEglFSKmsEglDevice(this, screenConfig(), deviceName); } bool QEglFSKmsEglDeviceIntegration::query_egl_device() @@ -283,7 +280,11 @@ bool QEglFSKmsEglDeviceIntegration::query_egl_device() QPlatformCursor *QEglFSKmsEglDeviceIntegration::createCursor(QPlatformScreen *screen) const { - return separateScreens() ? new QEglFSCursor(screen) : nullptr; +#if QT_CONFIG(opengl) + if (screenConfig()->separateScreens()) + return new QEglFSCursor(screen); +#endif + return nullptr; } QT_END_NAMESPACE diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldeviceintegration.h b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldeviceintegration.h index cddfdbd5c6..62404cfcd1 100644 --- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldeviceintegration.h +++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldeviceintegration.h @@ -55,27 +55,26 @@ class QEglFSKmsEglDeviceIntegration : public QEglFSKmsIntegration public: QEglFSKmsEglDeviceIntegration(); - EGLint surfaceType() const Q_DECL_OVERRIDE; - EGLDisplay createDisplay(EGLNativeDisplayType nativeDisplay) Q_DECL_OVERRIDE; - bool supportsSurfacelessContexts() const Q_DECL_OVERRIDE; - bool supportsPBuffers() const Q_DECL_OVERRIDE; - QEglFSWindow *createWindow(QWindow *window) const Q_DECL_OVERRIDE; + EGLint surfaceType() const override; + EGLDisplay createDisplay(EGLNativeDisplayType nativeDisplay) override; + bool supportsSurfacelessContexts() const override; + bool supportsPBuffers() const override; + QEglFSWindow *createWindow(QWindow *window) const override; EGLDeviceEXT eglDevice() const { return m_egl_device; } protected: - QEglFSKmsDevice *createDevice(const QString &devicePath) Q_DECL_OVERRIDE; - QPlatformCursor *createCursor(QPlatformScreen *screen) const Q_DECL_OVERRIDE; + QKmsDevice *createDevice() override; + QPlatformCursor *createCursor(QPlatformScreen *screen) const override; private: bool setup_kms(); bool query_egl_device(); EGLDeviceEXT m_egl_device; - - friend class QEglJetsonTK1Window; - // EGLStream infrastructure QEGLStreamConvenience *m_funcs; + + friend class QEglFSKmsEglDeviceWindow; }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldevicemain.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldevicemain.cpp index 42fec073f1..5763ab45cc 100644 --- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldevicemain.cpp +++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldevicemain.cpp @@ -47,7 +47,7 @@ class QEglFSKmsEglDeviceIntegrationPlugin : public QEglFSDeviceIntegrationPlugin Q_PLUGIN_METADATA(IID QEglFSDeviceIntegrationFactoryInterface_iid FILE "eglfs_kms_egldevice.json") public: - QEglFSDeviceIntegration *create() Q_DECL_OVERRIDE { return new QEglFSKmsEglDeviceIntegration; } + QEglFSDeviceIntegration *create() override { return new QEglFSKmsEglDeviceIntegration; } }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldevicescreen.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldevicescreen.cpp index 3935c99b9e..a27c89faab 100644 --- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldevicescreen.cpp +++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldevicescreen.cpp @@ -40,11 +40,15 @@ #include "qeglfskmsegldevicescreen.h" #include "qeglfskmsegldevice.h" #include <QGuiApplication> +#include <QLoggingCategory> +#include <errno.h> QT_BEGIN_NAMESPACE -QEglFSKmsEglDeviceScreen::QEglFSKmsEglDeviceScreen(QEglFSKmsIntegration *integration, QEglFSKmsDevice *device, QEglFSKmsOutput output) - : QEglFSKmsScreen(integration, device, output) +Q_DECLARE_LOGGING_CATEGORY(qLcEglfsKmsDebug) + +QEglFSKmsEglDeviceScreen::QEglFSKmsEglDeviceScreen(QKmsDevice *device, const QKmsOutput &output) + : QEglFSKmsScreen(device, output) { } @@ -52,7 +56,7 @@ QEglFSKmsEglDeviceScreen::~QEglFSKmsEglDeviceScreen() { const int remainingScreenCount = qGuiApp->screens().count(); qCDebug(qLcEglfsKmsDebug, "Screen dtor. Remaining screens: %d", remainingScreenCount); - if (!remainingScreenCount && !m_integration->separateScreens()) + if (!remainingScreenCount && !device()->screenConfig()->separateScreens()) static_cast<QEglFSKmsEglDevice *>(device())->destroyGlobalCursor(); } @@ -62,12 +66,15 @@ QPlatformCursor *QEglFSKmsEglDeviceScreen::cursor() const // in its ctor. With separateScreens just use that. Otherwise // there's a virtual desktop and the device has a global cursor // and the base class has no dedicated cursor at all. - return m_integration->separateScreens() ? QEglFSScreen::cursor() : static_cast<QEglFSKmsEglDevice *>(device())->globalCursor(); + // config->hwCursor() is ignored for now, just use the standard OpenGL cursor. + return device()->screenConfig()->separateScreens() + ? QEglFSScreen::cursor() + : static_cast<QEglFSKmsEglDevice *>(device())->globalCursor(); } void QEglFSKmsEglDeviceScreen::waitForFlip() { - QEglFSKmsOutput &op(output()); + QKmsOutput &op(output()); const int fd = device()->fd(); const uint32_t w = op.modes[op.mode].hdisplay; const uint32_t h = op.modes[op.mode].vdisplay; diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldevicescreen.h b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldevicescreen.h index c57f52c6b7..5efe35f8b3 100644 --- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldevicescreen.h +++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldevicescreen.h @@ -47,14 +47,12 @@ QT_BEGIN_NAMESPACE class QEglFSKmsEglDeviceScreen : public QEglFSKmsScreen { public: - QEglFSKmsEglDeviceScreen(QEglFSKmsIntegration *integration, - QEglFSKmsDevice *device, - QEglFSKmsOutput output); + QEglFSKmsEglDeviceScreen(QKmsDevice *device, const QKmsOutput &output); ~QEglFSKmsEglDeviceScreen(); - QPlatformCursor *cursor() const Q_DECL_OVERRIDE; + QPlatformCursor *cursor() const override; - void waitForFlip() Q_DECL_OVERRIDE; + void waitForFlip() override; }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/eglfs_kms_support.pro b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/eglfs_kms_support.pro index 487edb569e..3c0a0ce30f 100644 --- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/eglfs_kms_support.pro +++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/eglfs_kms_support.pro @@ -2,7 +2,7 @@ TARGET = QtEglFsKmsSupport CONFIG += no_module_headers internal_module load(qt_module) -QT += core-private gui-private eglfsdeviceintegration-private +QT += core-private gui-private eglfsdeviceintegration-private kms_support-private INCLUDEPATH += $$PWD/../../api @@ -15,8 +15,8 @@ QMAKE_LFLAGS += $$QMAKE_LFLAGS_NOUNDEF SOURCES += $$PWD/qeglfskmsintegration.cpp \ $$PWD/qeglfskmsdevice.cpp \ - $$PWD/qeglfskmsscreen.cpp \ + $$PWD/qeglfskmsscreen.cpp HEADERS += $$PWD/qeglfskmsintegration.h \ $$PWD/qeglfskmsdevice.h \ - $$PWD/qeglfskmsscreen.h \ + $$PWD/qeglfskmsscreen.h diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsdevice.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsdevice.cpp index f372b9d156..b073577797 100644 --- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsdevice.cpp +++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsdevice.cpp @@ -1,6 +1,5 @@ /**************************************************************************** ** -** Copyright (C) 2015 Pier Luigi Fiorini <pierluigi.fiorini@gmail.com> ** Copyright (C) 2016 The Qt Company Ltd. ** Copyright (C) 2016 Pelagicore AG ** Contact: https://www.qt.io/licensing/ @@ -41,464 +40,25 @@ #include "qeglfskmsdevice.h" #include "qeglfskmsscreen.h" - -#include "qeglfsintegration_p.h" - -#include <QtCore/QLoggingCategory> -#include <QtCore/private/qcore_unix_p.h> +#include "private/qeglfsintegration_p.h" #include <QtGui/private/qguiapplication_p.h> -#define ARRAY_LENGTH(a) (sizeof (a) / sizeof (a)[0]) - QT_BEGIN_NAMESPACE -Q_DECLARE_LOGGING_CATEGORY(qLcEglfsKmsDebug) - -enum OutputConfiguration { - OutputConfigOff, - OutputConfigPreferred, - OutputConfigCurrent, - OutputConfigMode, - OutputConfigModeline -}; - -int QEglFSKmsDevice::crtcForConnector(drmModeResPtr resources, drmModeConnectorPtr connector) -{ - for (int i = 0; i < connector->count_encoders; i++) { - drmModeEncoderPtr encoder = drmModeGetEncoder(m_dri_fd, connector->encoders[i]); - if (!encoder) { - qWarning("Failed to get encoder"); - continue; - } - - quint32 possibleCrtcs = encoder->possible_crtcs; - drmModeFreeEncoder(encoder); - - for (int j = 0; j < resources->count_crtcs; j++) { - bool isPossible = possibleCrtcs & (1 << j); - bool isAvailable = !(m_crtc_allocator & 1 << resources->crtcs[j]); - - if (isPossible && isAvailable) - return j; - } - } - - return -1; -} - -static const char * const connector_type_names[] = { // must match DRM_MODE_CONNECTOR_* - "None", - "VGA", - "DVI", - "DVI", - "DVI", - "Composite", - "TV", - "LVDS", - "CTV", - "DIN", - "DP", - "HDMI", - "HDMI", - "TV", - "eDP", - "Virtual", - "DSI" -}; - -static QByteArray nameForConnector(const drmModeConnectorPtr connector) -{ - const QByteArray id = QByteArray::number(connector->connector_type_id); - if (connector->connector_type < ARRAY_LENGTH(connector_type_names)) - return connector_type_names[connector->connector_type] + id; - return "UNKNOWN" + id; -} - -static bool parseModeline(const QByteArray &text, drmModeModeInfoPtr mode) -{ - char hsync[16]; - char vsync[16]; - float fclock; - - mode->type = DRM_MODE_TYPE_USERDEF; - mode->hskew = 0; - mode->vscan = 0; - mode->vrefresh = 0; - mode->flags = 0; - - if (sscanf(text.constData(), "%f %hd %hd %hd %hd %hd %hd %hd %hd %15s %15s", - &fclock, - &mode->hdisplay, - &mode->hsync_start, - &mode->hsync_end, - &mode->htotal, - &mode->vdisplay, - &mode->vsync_start, - &mode->vsync_end, - &mode->vtotal, hsync, vsync) != 11) - return false; - - mode->clock = fclock * 1000; - - if (strcmp(hsync, "+hsync") == 0) - mode->flags |= DRM_MODE_FLAG_PHSYNC; - else if (strcmp(hsync, "-hsync") == 0) - mode->flags |= DRM_MODE_FLAG_NHSYNC; - else - return false; - - if (strcmp(vsync, "+vsync") == 0) - mode->flags |= DRM_MODE_FLAG_PVSYNC; - else if (strcmp(vsync, "-vsync") == 0) - mode->flags |= DRM_MODE_FLAG_NVSYNC; - else - return false; - - return true; -} - -QEglFSKmsScreen *QEglFSKmsDevice::createScreenForConnector(drmModeResPtr resources, - drmModeConnectorPtr connector, - VirtualDesktopInfo *vinfo) -{ - const QByteArray connectorName = nameForConnector(connector); - - const int crtc = crtcForConnector(resources, connector); - if (crtc < 0) { - qWarning() << "No usable crtc/encoder pair for connector" << connectorName; - return Q_NULLPTR; - } - - OutputConfiguration configuration; - QSize configurationSize; - drmModeModeInfo configurationModeline; - - auto userConfig = m_integration->outputSettings(); - auto userConnectorConfig = userConfig.value(QString::fromUtf8(connectorName)); - // default to the preferred mode unless overridden in the config - const QByteArray mode = userConnectorConfig.value(QStringLiteral("mode"), QStringLiteral("preferred")) - .toByteArray().toLower(); - if (mode == "off") { - configuration = OutputConfigOff; - } else if (mode == "preferred") { - configuration = OutputConfigPreferred; - } else if (mode == "current") { - configuration = OutputConfigCurrent; - } else if (sscanf(mode.constData(), "%dx%d", &configurationSize.rwidth(), &configurationSize.rheight()) == 2) { - configuration = OutputConfigMode; - } else if (parseModeline(mode, &configurationModeline)) { - configuration = OutputConfigModeline; - } else { - qWarning("Invalid mode \"%s\" for output %s", mode.constData(), connectorName.constData()); - configuration = OutputConfigPreferred; - } - if (vinfo) { - *vinfo = VirtualDesktopInfo(); - vinfo->virtualIndex = userConnectorConfig.value(QStringLiteral("virtualIndex"), INT_MAX).toInt(); - if (userConnectorConfig.contains(QStringLiteral("virtualPos"))) { - const QByteArray vpos = userConnectorConfig.value(QStringLiteral("virtualPos")).toByteArray(); - const QByteArrayList vposComp = vpos.split(','); - if (vposComp.count() == 2) - vinfo->virtualPos = QPoint(vposComp[0].trimmed().toInt(), vposComp[1].trimmed().toInt()); - } - } - - const uint32_t crtc_id = resources->crtcs[crtc]; - - if (configuration == OutputConfigOff) { - qCDebug(qLcEglfsKmsDebug) << "Turning off output" << connectorName; - drmModeSetCrtc(m_dri_fd, crtc_id, 0, 0, 0, 0, 0, Q_NULLPTR); - return Q_NULLPTR; - } - - // Skip disconnected output - if (configuration == OutputConfigPreferred && connector->connection == DRM_MODE_DISCONNECTED) { - qCDebug(qLcEglfsKmsDebug) << "Skipping disconnected output" << connectorName; - return Q_NULLPTR; - } - - // Get the current mode on the current crtc - drmModeModeInfo crtc_mode; - memset(&crtc_mode, 0, sizeof crtc_mode); - if (drmModeEncoderPtr encoder = drmModeGetEncoder(m_dri_fd, connector->connector_id)) { - drmModeCrtcPtr crtc = drmModeGetCrtc(m_dri_fd, encoder->crtc_id); - drmModeFreeEncoder(encoder); - - if (!crtc) - return Q_NULLPTR; - - if (crtc->mode_valid) - crtc_mode = crtc->mode; - - drmModeFreeCrtc(crtc); - } - - QList<drmModeModeInfo> modes; - modes.reserve(connector->count_modes); - qCDebug(qLcEglfsKmsDebug) << connectorName << "mode count:" << connector->count_modes; - for (int i = 0; i < connector->count_modes; i++) { - const drmModeModeInfo &mode = connector->modes[i]; - qCDebug(qLcEglfsKmsDebug) << "mode" << i << mode.hdisplay << "x" << mode.vdisplay - << '@' << mode.vrefresh << "hz"; - modes << connector->modes[i]; - } - - int preferred = -1; - int current = -1; - int configured = -1; - int best = -1; - - for (int i = modes.size() - 1; i >= 0; i--) { - const drmModeModeInfo &m = modes.at(i); - - if (configuration == OutputConfigMode && - m.hdisplay == configurationSize.width() && - m.vdisplay == configurationSize.height()) { - configured = i; - } - - if (!memcmp(&crtc_mode, &m, sizeof m)) - current = i; - - if (m.type & DRM_MODE_TYPE_PREFERRED) - preferred = i; - - best = i; - } - - if (configuration == OutputConfigModeline) { - modes << configurationModeline; - configured = modes.size() - 1; - } - - if (current < 0 && crtc_mode.clock != 0) { - modes << crtc_mode; - current = mode.size() - 1; - } - - if (configuration == OutputConfigCurrent) - configured = current; - - int selected_mode = -1; - - if (configured >= 0) - selected_mode = configured; - else if (preferred >= 0) - selected_mode = preferred; - else if (current >= 0) - selected_mode = current; - else if (best >= 0) - selected_mode = best; - - if (selected_mode < 0) { - qWarning() << "No modes available for output" << connectorName; - return Q_NULLPTR; - } else { - int width = modes[selected_mode].hdisplay; - int height = modes[selected_mode].vdisplay; - int refresh = modes[selected_mode].vrefresh; - qCDebug(qLcEglfsKmsDebug) << "Selected mode" << selected_mode << ":" << width << "x" << height - << '@' << refresh << "hz for output" << connectorName; - } - - // physical size from connector < config values < env vars - static const int width = qEnvironmentVariableIntValue("QT_QPA_EGLFS_PHYSICAL_WIDTH"); - static const int height = qEnvironmentVariableIntValue("QT_QPA_EGLFS_PHYSICAL_HEIGHT"); - QSizeF physSize(width, height); - if (physSize.isEmpty()) { - physSize = QSize(userConnectorConfig.value(QStringLiteral("physicalWidth")).toInt(), - userConnectorConfig.value(QStringLiteral("physicalHeight")).toInt()); - if (physSize.isEmpty()) { - physSize.setWidth(connector->mmWidth); - physSize.setHeight(connector->mmHeight); - } - } - qCDebug(qLcEglfsKmsDebug) << "Physical size is" << physSize << "mm" << "for output" << connectorName; - - QEglFSKmsOutput output = { - QString::fromUtf8(connectorName), - connector->connector_id, - crtc_id, - physSize, - selected_mode, - false, - drmModeGetCrtc(m_dri_fd, crtc_id), - modes, - connector->subpixel, - connectorProperty(connector, QByteArrayLiteral("DPMS")), - false, - 0, - false - }; - - bool ok; - int idx = qEnvironmentVariableIntValue("QT_QPA_EGLFS_KMS_PLANE_INDEX", &ok); - if (ok) { - drmModePlaneRes *planeResources = drmModeGetPlaneResources(m_dri_fd); - if (planeResources) { - if (idx >= 0 && idx < int(planeResources->count_planes)) { - drmModePlane *plane = drmModeGetPlane(m_dri_fd, planeResources->planes[idx]); - if (plane) { - output.wants_plane = true; - output.plane_id = plane->plane_id; - qCDebug(qLcEglfsKmsDebug, "Forcing plane index %d, plane id %u (belongs to crtc id %u)", - idx, plane->plane_id, plane->crtc_id); - drmModeFreePlane(plane); - } - } else { - qWarning("Invalid plane index %d, must be between 0 and %u", idx, planeResources->count_planes - 1); - } - } - } - - m_crtc_allocator |= (1 << output.crtc_id); - m_connector_allocator |= (1 << output.connector_id); - - return createScreen(m_integration, this, output); -} - -drmModePropertyPtr QEglFSKmsDevice::connectorProperty(drmModeConnectorPtr connector, const QByteArray &name) -{ - drmModePropertyPtr prop; - - for (int i = 0; i < connector->count_props; i++) { - prop = drmModeGetProperty(m_dri_fd, connector->props[i]); - if (!prop) - continue; - if (strcmp(prop->name, name.constData()) == 0) - return prop; - drmModeFreeProperty(prop); - } - - return Q_NULLPTR; -} - -QEglFSKmsDevice::QEglFSKmsDevice(QEglFSKmsIntegration *integration, const QString &path) - : m_integration(integration) - , m_path(path) - , m_dri_fd(-1) - , m_crtc_allocator(0) - , m_connector_allocator(0) -{ -} - -QEglFSKmsDevice::~QEglFSKmsDevice() -{ -} - -struct OrderedScreen -{ - OrderedScreen() : screen(nullptr) { } - OrderedScreen(QEglFSKmsScreen *screen, const QEglFSKmsDevice::VirtualDesktopInfo &vinfo) - : screen(screen), vinfo(vinfo) { } - QEglFSKmsScreen *screen; - QEglFSKmsDevice::VirtualDesktopInfo vinfo; -}; - -QDebug operator<<(QDebug dbg, const OrderedScreen &s) -{ - QDebugStateSaver saver(dbg); - dbg.nospace() << "OrderedScreen(" << s.screen << " : " << s.vinfo.virtualIndex - << " / " << s.vinfo.virtualPos << ")"; - return dbg; -} - -static bool orderedScreenLessThan(const OrderedScreen &a, const OrderedScreen &b) -{ - return a.vinfo.virtualIndex < b.vinfo.virtualIndex; -} - -void QEglFSKmsDevice::createScreens() -{ - drmModeResPtr resources = drmModeGetResources(m_dri_fd); - if (!resources) { - qWarning("drmModeGetResources failed"); - return; - } - - QVector<OrderedScreen> screens; - - int wantedConnectorIndex = -1; - bool ok; - int idx = qEnvironmentVariableIntValue("QT_QPA_EGLFS_KMS_CONNECTOR_INDEX", &ok); - if (ok) { - if (idx >= 0 && idx < resources->count_connectors) - wantedConnectorIndex = idx; - else - qWarning("Invalid connector index %d, must be between 0 and %u", idx, resources->count_connectors - 1); - } - - for (int i = 0; i < resources->count_connectors; i++) { - if (wantedConnectorIndex >= 0 && i != wantedConnectorIndex) - continue; - - drmModeConnectorPtr connector = drmModeGetConnector(m_dri_fd, resources->connectors[i]); - if (!connector) - continue; - - VirtualDesktopInfo vinfo; - QEglFSKmsScreen *screen = createScreenForConnector(resources, connector, &vinfo); - if (screen) - screens.append(OrderedScreen(screen, vinfo)); - - drmModeFreeConnector(connector); - } - - drmModeFreeResources(resources); - - // Use stable sort to preserve the original order for outputs with unspecified indices. - std::stable_sort(screens.begin(), screens.end(), orderedScreenLessThan); - qCDebug(qLcEglfsKmsDebug) << "Sorted screen list:" << screens; - - QPoint pos(0, 0); - QList<QPlatformScreen *> siblings; - QEglFSIntegration *qpaIntegration = static_cast<QEglFSIntegration *>(QGuiApplicationPrivate::platformIntegration()); - - for (const OrderedScreen &orderedScreen : screens) { - QEglFSKmsScreen *s = orderedScreen.screen; - // set up a horizontal or vertical virtual desktop - if (orderedScreen.vinfo.virtualPos.isNull()) { - s->setVirtualPosition(pos); - if (m_integration->virtualDesktopLayout() == QEglFSKmsIntegration::VirtualDesktopLayoutVertical) - pos.ry() += s->geometry().height(); - else - pos.rx() += s->geometry().width(); - } else { - s->setVirtualPosition(orderedScreen.vinfo.virtualPos); - } - qCDebug(qLcEglfsKmsDebug) << "Adding screen" << s << "to QPA with geometry" << s->geometry(); - // The order in qguiapp's screens list will match the order set by - // virtualIndex. This is not only handy but also required since for instance - // evdevtouch relies on it when performing touch device - screen mapping. - qpaIntegration->addScreen(s); - siblings << s; - } - - if (!m_integration->separateScreens()) { - // enable the virtual desktop - Q_FOREACH (QPlatformScreen *screen, siblings) - static_cast<QEglFSKmsScreen *>(screen)->setVirtualSiblings(siblings); - } -} - -int QEglFSKmsDevice::fd() const -{ - return m_dri_fd; -} - -QString QEglFSKmsDevice::devicePath() const -{ - return m_path; -} - -QEglFSKmsScreen *QEglFSKmsDevice::createScreen(QEglFSKmsIntegration *integration, QEglFSKmsDevice *device, QEglFSKmsOutput output) +QEglFSKmsDevice::QEglFSKmsDevice(QKmsScreenConfig *screenConfig, const QString &path) + : QKmsDevice(screenConfig, path) { - return new QEglFSKmsScreen(integration, device, output); } -void QEglFSKmsDevice::setFd(int fd) +void QEglFSKmsDevice::registerScreen(QPlatformScreen *screen, + bool isPrimary, + const QPoint &virtualPos, + const QList<QPlatformScreen *> &virtualSiblings) { - m_dri_fd = fd; + QEglFSKmsScreen *s = static_cast<QEglFSKmsScreen *>(screen); + s->setVirtualPosition(virtualPos); + s->setVirtualSiblings(virtualSiblings); + static_cast<QEglFSIntegration *>(QGuiApplicationPrivate::platformIntegration())->addScreen(s, isPrimary); } QT_END_NAMESPACE diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsdevice.h b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsdevice.h index 3e7ac7e3f0..fc83a620d9 100644 --- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsdevice.h +++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsdevice.h @@ -1,6 +1,5 @@ /**************************************************************************** ** -** Copyright (C) 2015 Pier Luigi Fiorini <pierluigi.fiorini@gmail.com> ** Copyright (C) 2016 The Qt Company Ltd. ** Copyright (C) 2016 Pelagicore AG ** Contact: https://www.qt.io/licensing/ @@ -42,64 +41,22 @@ #ifndef QEGLFSKMSDEVICE_H #define QEGLFSKMSDEVICE_H -#include "qeglfskmsintegration.h" -#include "qeglfskmsscreen.h" - -#include <xf86drm.h> -#include <xf86drmMode.h> +#include "private/qeglfsglobal_p.h" +#include <QtKmsSupport/private/qkmsdevice_p.h> QT_BEGIN_NAMESPACE -class Q_EGLFS_EXPORT QEglFSKmsDevice +class Q_EGLFS_EXPORT QEglFSKmsDevice : public QKmsDevice { public: - struct VirtualDesktopInfo { - VirtualDesktopInfo() : virtualIndex(0) { } - int virtualIndex; - QPoint virtualPos; - }; - - QEglFSKmsDevice(QEglFSKmsIntegration *integration, const QString &path); - virtual ~QEglFSKmsDevice(); - - virtual bool open() = 0; - virtual void close() = 0; - - virtual void createScreens(); - - virtual EGLNativeDisplayType nativeDisplay() const = 0; - int fd() const; - QString devicePath() const; - -protected: - virtual QEglFSKmsScreen *createScreen(QEglFSKmsIntegration *integration, - QEglFSKmsDevice *device, - QEglFSKmsOutput output); - void setFd(int fd); - - QEglFSKmsIntegration *m_integration; - QString m_path; - int m_dri_fd; - - quint32 m_crtc_allocator; - quint32 m_connector_allocator; - - int crtcForConnector(drmModeResPtr resources, drmModeConnectorPtr connector); - QEglFSKmsScreen *createScreenForConnector(drmModeResPtr resources, - drmModeConnectorPtr connector, - VirtualDesktopInfo *vinfo); - drmModePropertyPtr connectorProperty(drmModeConnectorPtr connector, const QByteArray &name); - - static void pageFlipHandler(int fd, - unsigned int sequence, - unsigned int tv_sec, - unsigned int tv_usec, - void *user_data); + QEglFSKmsDevice(QKmsScreenConfig *screenConfig, const QString &path); -private: - Q_DISABLE_COPY(QEglFSKmsDevice) + void registerScreen(QPlatformScreen *screen, + bool isPrimary, + const QPoint &virtualPos, + const QList<QPlatformScreen *> &virtualSiblings) override; }; QT_END_NAMESPACE -#endif +#endif // QEGLFSKMSDEVICE_H diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsintegration.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsintegration.cpp index 5368a6d031..c77151181e 100644 --- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsintegration.cpp +++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsintegration.cpp @@ -40,13 +40,10 @@ ****************************************************************************/ #include "qeglfskmsintegration.h" -#include "qeglfskmsdevice.h" #include "qeglfskmsscreen.h" -#include <QtCore/QJsonDocument> -#include <QtCore/QJsonObject> -#include <QtCore/QJsonArray> -#include <QtCore/QFile> +#include <QtKmsSupport/private/qkmsdevice_p.h> + #include <QtGui/qpa/qplatformwindow.h> #include <QtGui/QScreen> @@ -58,28 +55,27 @@ QT_BEGIN_NAMESPACE Q_LOGGING_CATEGORY(qLcEglfsKmsDebug, "qt.qpa.eglfs.kms") QEglFSKmsIntegration::QEglFSKmsIntegration() - : m_device(Q_NULLPTR) - , m_hwCursor(false) - , m_pbuffers(false) - , m_separateScreens(false) - , m_virtualDesktopLayout(VirtualDesktopLayoutHorizontal) -{} - -void QEglFSKmsIntegration::platformInit() + : m_device(Q_NULLPTR), + m_screenConfig(new QKmsScreenConfig) { - loadConfig(); +} - if (!m_devicePath.isEmpty()) { - qCDebug(qLcEglfsKmsDebug) << "Using DRM device" << m_devicePath << "specified in config file"; - } +QEglFSKmsIntegration::~QEglFSKmsIntegration() +{ + delete m_screenConfig; +} - m_device = createDevice(m_devicePath); +void QEglFSKmsIntegration::platformInit() +{ + qCDebug(qLcEglfsKmsDebug, "platformInit: Opening DRM device"); + m_device = createDevice(); if (Q_UNLIKELY(!m_device->open())) - qFatal("Could not open device %s - aborting!", qPrintable(m_devicePath)); + qFatal("Could not open DRM device"); } void QEglFSKmsIntegration::platformDestroy() { + qCDebug(qLcEglfsKmsDebug, "platformDestroy: Closing DRM device"); m_device->close(); delete m_device; m_device = Q_NULLPTR; @@ -88,7 +84,7 @@ void QEglFSKmsIntegration::platformDestroy() EGLNativeDisplayType QEglFSKmsIntegration::platformDisplay() const { Q_ASSERT(m_device); - return m_device->nativeDisplay(); + return (EGLNativeDisplayType) m_device->nativeDisplay(); } bool QEglFSKmsIntegration::usesDefaultScreen() @@ -134,94 +130,17 @@ void QEglFSKmsIntegration::waitForVSync(QPlatformSurface *surface) const bool QEglFSKmsIntegration::supportsPBuffers() const { - return m_pbuffers; -} - -bool QEglFSKmsIntegration::hwCursor() const -{ - return m_hwCursor; -} - -bool QEglFSKmsIntegration::separateScreens() const -{ - return m_separateScreens; -} - -QEglFSKmsIntegration::VirtualDesktopLayout QEglFSKmsIntegration::virtualDesktopLayout() const -{ - return m_virtualDesktopLayout; + return m_screenConfig->supportsPBuffers(); } -QMap<QString, QVariantMap> QEglFSKmsIntegration::outputSettings() const -{ - return m_outputSettings; -} - -QEglFSKmsDevice *QEglFSKmsIntegration::device() const +QKmsDevice *QEglFSKmsIntegration::device() const { return m_device; } -void QEglFSKmsIntegration::loadConfig() +QKmsScreenConfig *QEglFSKmsIntegration::screenConfig() const { - static QByteArray json = qgetenv("QT_QPA_EGLFS_KMS_CONFIG"); - if (json.isEmpty()) - return; - - qCDebug(qLcEglfsKmsDebug) << "Loading KMS setup from" << json; - - QFile file(QString::fromUtf8(json)); - if (!file.open(QFile::ReadOnly)) { - qCWarning(qLcEglfsKmsDebug) << "Could not open config file" - << json << "for reading"; - return; - } - - const QJsonDocument doc = QJsonDocument::fromJson(file.readAll()); - if (!doc.isObject()) { - qCWarning(qLcEglfsKmsDebug) << "Invalid config file" << json - << "- no top-level JSON object"; - return; - } - - const QJsonObject object = doc.object(); - - m_hwCursor = object.value(QLatin1String("hwcursor")).toBool(m_hwCursor); - m_pbuffers = object.value(QLatin1String("pbuffers")).toBool(m_pbuffers); - m_devicePath = object.value(QLatin1String("device")).toString(); - m_separateScreens = object.value(QLatin1String("separateScreens")).toBool(m_separateScreens); - - const QString vdOriString = object.value(QLatin1String("virtualDesktopLayout")).toString(); - if (!vdOriString.isEmpty()) { - if (vdOriString == QLatin1String("horizontal")) - m_virtualDesktopLayout = VirtualDesktopLayoutHorizontal; - else if (vdOriString == QLatin1String("vertical")) - m_virtualDesktopLayout = VirtualDesktopLayoutVertical; - else - qCWarning(qLcEglfsKmsDebug) << "Unknown virtualDesktopOrientation value" << vdOriString; - } - - const QJsonArray outputs = object.value(QLatin1String("outputs")).toArray(); - for (int i = 0; i < outputs.size(); i++) { - const QVariantMap outputSettings = outputs.at(i).toObject().toVariantMap(); - - if (outputSettings.contains(QStringLiteral("name"))) { - const QString name = outputSettings.value(QStringLiteral("name")).toString(); - - if (m_outputSettings.contains(name)) { - qCDebug(qLcEglfsKmsDebug) << "Output" << name << "configured multiple times!"; - } - - m_outputSettings.insert(name, outputSettings); - } - } - - qCDebug(qLcEglfsKmsDebug) << "Configuration:\n" - << "\thwcursor:" << m_hwCursor << "\n" - << "\tpbuffers:" << m_pbuffers << "\n" - << "\tseparateScreens:" << m_separateScreens << "\n" - << "\tvirtualDesktopLayout:" << m_virtualDesktopLayout << "\n" - << "\toutputs:" << m_outputSettings; + return m_screenConfig; } QT_END_NAMESPACE diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsintegration.h b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsintegration.h index ba49945715..9955616919 100644 --- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsintegration.h +++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsintegration.h @@ -49,49 +49,35 @@ QT_BEGIN_NAMESPACE -class QEglFSKmsDevice; +class QKmsDevice; +class QKmsScreenConfig; Q_EGLFS_EXPORT Q_DECLARE_LOGGING_CATEGORY(qLcEglfsKmsDebug) class Q_EGLFS_EXPORT QEglFSKmsIntegration : public QEglFSDeviceIntegration { public: - enum VirtualDesktopLayout { - VirtualDesktopLayoutHorizontal, - VirtualDesktopLayoutVertical - }; - QEglFSKmsIntegration(); + ~QEglFSKmsIntegration(); - void platformInit() Q_DECL_OVERRIDE; - void platformDestroy() Q_DECL_OVERRIDE; - EGLNativeDisplayType platformDisplay() const Q_DECL_OVERRIDE; - bool usesDefaultScreen() Q_DECL_OVERRIDE; - void screenInit() Q_DECL_OVERRIDE; - QSurfaceFormat surfaceFormatFor(const QSurfaceFormat &inputFormat) const Q_DECL_OVERRIDE; - bool hasCapability(QPlatformIntegration::Capability cap) const Q_DECL_OVERRIDE; - void waitForVSync(QPlatformSurface *surface) const Q_DECL_OVERRIDE; - bool supportsPBuffers() const Q_DECL_OVERRIDE; - - virtual bool hwCursor() const; - virtual bool separateScreens() const; - virtual VirtualDesktopLayout virtualDesktopLayout() const; - QMap<QString, QVariantMap> outputSettings() const; + void platformInit() override; + void platformDestroy() override; + EGLNativeDisplayType platformDisplay() const override; + bool usesDefaultScreen() override; + void screenInit() override; + QSurfaceFormat surfaceFormatFor(const QSurfaceFormat &inputFormat) const override; + bool hasCapability(QPlatformIntegration::Capability cap) const override; + void waitForVSync(QPlatformSurface *surface) const override; + bool supportsPBuffers() const override; - QEglFSKmsDevice *device() const; + QKmsDevice *device() const; + QKmsScreenConfig *screenConfig() const; protected: - virtual QEglFSKmsDevice *createDevice(const QString &devicePath) = 0; - - void loadConfig(); + virtual QKmsDevice *createDevice() = 0; - QEglFSKmsDevice *m_device; - bool m_hwCursor; - bool m_pbuffers; - bool m_separateScreens; - VirtualDesktopLayout m_virtualDesktopLayout; - QString m_devicePath; - QMap<QString, QVariantMap> m_outputSettings; + QKmsDevice *m_device; + QKmsScreenConfig *m_screenConfig; }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsscreen.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsscreen.cpp index 4021609407..3951f46a82 100644 --- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsscreen.cpp +++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsscreen.cpp @@ -40,7 +40,6 @@ ****************************************************************************/ #include "qeglfskmsscreen.h" -#include "qeglfskmsdevice.h" #include "qeglfsintegration_p.h" #include <QtCore/QLoggingCategory> @@ -69,30 +68,19 @@ private: QEglFSKmsScreen *m_screen; }; -QEglFSKmsScreen::QEglFSKmsScreen(QEglFSKmsIntegration *integration, - QEglFSKmsDevice *device, - QEglFSKmsOutput output) - : QEglFSScreen(eglGetDisplay(device->nativeDisplay())) - , m_integration(integration) +QEglFSKmsScreen::QEglFSKmsScreen(QKmsDevice *device, const QKmsOutput &output) + : QEglFSScreen(eglGetDisplay((EGLNativeDisplayType) device->nativeDisplay())) , m_device(device) , m_output(output) , m_powerState(PowerStateOn) , m_interruptHandler(new QEglFSKmsInterruptHandler(this)) { - m_siblings << this; // gets overridden by QEglFSKmsDevice later if !separateScreens + m_siblings << this; // gets overridden later } QEglFSKmsScreen::~QEglFSKmsScreen() { - if (m_output.dpms_prop) { - drmModeFreeProperty(m_output.dpms_prop); - m_output.dpms_prop = Q_NULLPTR; - } - restoreMode(); - if (m_output.saved_crtc) { - drmModeFreeCrtc(m_output.saved_crtc); - m_output.saved_crtc = Q_NULLPTR; - } + m_output.cleanup(m_device); delete m_interruptHandler; } @@ -123,7 +111,12 @@ QImage::Format QEglFSKmsScreen::format() const QSizeF QEglFSKmsScreen::physicalSize() const { - return m_output.physical_size; + if (!m_output.physical_size.isEmpty()) { + return m_output.physical_size; + } else { + const QSize s = geometry().size(); + return QSizeF(0.254 * s.width(), 0.254 * s.height()); + } } QDpi QEglFSKmsScreen::logicalDpi() const @@ -171,16 +164,7 @@ void QEglFSKmsScreen::flipFinished() void QEglFSKmsScreen::restoreMode() { - if (m_output.mode_set && m_output.saved_crtc) { - drmModeSetCrtc(m_device->fd(), - m_output.saved_crtc->crtc_id, - m_output.saved_crtc->buffer_id, - 0, 0, - &m_output.connector_id, 1, - &m_output.saved_crtc->mode); - - m_output.mode_set = false; - } + m_output.restoreMode(m_device); } qreal QEglFSKmsScreen::refreshRate() const @@ -191,20 +175,7 @@ qreal QEglFSKmsScreen::refreshRate() const QPlatformScreen::SubpixelAntialiasingType QEglFSKmsScreen::subpixelAntialiasingTypeHint() const { - switch (m_output.subpixel) { - default: - case DRM_MODE_SUBPIXEL_UNKNOWN: - case DRM_MODE_SUBPIXEL_NONE: - return Subpixel_None; - case DRM_MODE_SUBPIXEL_HORIZONTAL_RGB: - return Subpixel_RGB; - case DRM_MODE_SUBPIXEL_HORIZONTAL_BGR: - return Subpixel_BGR; - case DRM_MODE_SUBPIXEL_VERTICAL_RGB: - return Subpixel_VRGB; - case DRM_MODE_SUBPIXEL_VERTICAL_BGR: - return Subpixel_VBGR; - } + return m_output.subpixelAntialiasingTypeHint(); } QPlatformScreen::PowerState QEglFSKmsScreen::powerState() const @@ -214,11 +185,7 @@ QPlatformScreen::PowerState QEglFSKmsScreen::powerState() const void QEglFSKmsScreen::setPowerState(QPlatformScreen::PowerState state) { - if (!m_output.dpms_prop) - return; - - drmModeConnectorSetProperty(m_device->fd(), m_output.connector_id, - m_output.dpms_prop->prop_id, (int)state); + m_output.setPowerState(m_device, state); m_powerState = state; } diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsscreen.h b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsscreen.h index fa331f0931..80bbb0c7f1 100644 --- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsscreen.h +++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsscreen.h @@ -42,65 +42,42 @@ #ifndef QEGLFSKMSSCREEN_H #define QEGLFSKMSSCREEN_H -#include "qeglfskmsintegration.h" #include "private/qeglfsscreen_p.h" #include <QtCore/QList> #include <QtCore/QMutex> -#include <xf86drm.h> -#include <xf86drmMode.h> +#include <QtKmsSupport/private/qkmsdevice_p.h> QT_BEGIN_NAMESPACE -class QEglFSKmsDevice; class QEglFSKmsInterruptHandler; -struct QEglFSKmsOutput -{ - QString name; - uint32_t connector_id; - uint32_t crtc_id; - QSizeF physical_size; - int mode; // index of selected mode in list below - bool mode_set; - drmModeCrtcPtr saved_crtc; - QList<drmModeModeInfo> modes; - int subpixel; - drmModePropertyPtr dpms_prop; - bool wants_plane; - uint32_t plane_id; - bool plane_set; -}; - class Q_EGLFS_EXPORT QEglFSKmsScreen : public QEglFSScreen { public: - QEglFSKmsScreen(QEglFSKmsIntegration *integration, - QEglFSKmsDevice *device, - QEglFSKmsOutput output); + QEglFSKmsScreen(QKmsDevice *device, const QKmsOutput &output); ~QEglFSKmsScreen(); void setVirtualPosition(const QPoint &pos); - QRect rawGeometry() const Q_DECL_OVERRIDE; + QRect rawGeometry() const override; - int depth() const Q_DECL_OVERRIDE; - QImage::Format format() const Q_DECL_OVERRIDE; + int depth() const override; + QImage::Format format() const override; - QSizeF physicalSize() const Q_DECL_OVERRIDE; - QDpi logicalDpi() const Q_DECL_OVERRIDE; - Qt::ScreenOrientation nativeOrientation() const Q_DECL_OVERRIDE; - Qt::ScreenOrientation orientation() const Q_DECL_OVERRIDE; + QSizeF physicalSize() const override; + QDpi logicalDpi() const override; + Qt::ScreenOrientation nativeOrientation() const override; + Qt::ScreenOrientation orientation() const override; - QString name() const Q_DECL_OVERRIDE; + QString name() const override; - qreal refreshRate() const Q_DECL_OVERRIDE; + qreal refreshRate() const override; - QList<QPlatformScreen *> virtualSiblings() const Q_DECL_OVERRIDE { return m_siblings; } + QList<QPlatformScreen *> virtualSiblings() const override { return m_siblings; } void setVirtualSiblings(QList<QPlatformScreen *> sl) { m_siblings = sl; } - QEglFSKmsIntegration *integration() const { return m_integration; } - QEglFSKmsDevice *device() const { return m_device; } + QKmsDevice *device() const { return m_device; } void destroySurface(); @@ -108,19 +85,18 @@ public: virtual void flip(); virtual void flipFinished(); - QEglFSKmsOutput &output() { return m_output; } + QKmsOutput &output() { return m_output; } void restoreMode(); - SubpixelAntialiasingType subpixelAntialiasingTypeHint() const Q_DECL_OVERRIDE; + SubpixelAntialiasingType subpixelAntialiasingTypeHint() const override; - QPlatformScreen::PowerState powerState() const Q_DECL_OVERRIDE; - void setPowerState(QPlatformScreen::PowerState state) Q_DECL_OVERRIDE; + QPlatformScreen::PowerState powerState() const override; + void setPowerState(QPlatformScreen::PowerState state) override; protected: - QEglFSKmsIntegration *m_integration; - QEglFSKmsDevice *m_device; + QKmsDevice *m_device; - QEglFSKmsOutput m_output; + QKmsOutput m_output; QPoint m_pos; QList<QPlatformScreen *> m_siblings; diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_mali/qeglfsmaliintegration.h b/src/plugins/platforms/eglfs/deviceintegration/eglfs_mali/qeglfsmaliintegration.h index 56883a3676..85eda4889f 100644 --- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_mali/qeglfsmaliintegration.h +++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_mali/qeglfsmaliintegration.h @@ -47,9 +47,9 @@ QT_BEGIN_NAMESPACE class QEglFSMaliIntegration : public QEglFSDeviceIntegration { public: - void platformInit() Q_DECL_OVERRIDE; - EGLNativeWindowType createNativeWindow(QPlatformWindow *window, const QSize &size, const QSurfaceFormat &format) Q_DECL_OVERRIDE; - void destroyNativeWindow(EGLNativeWindowType window) Q_DECL_OVERRIDE; + void platformInit() override; + EGLNativeWindowType createNativeWindow(QPlatformWindow *window, const QSize &size, const QSurfaceFormat &format) override; + void destroyNativeWindow(EGLNativeWindowType window) override; }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_mali/qeglfsmalimain.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_mali/qeglfsmalimain.cpp index a3c804f54d..4f87dab967 100644 --- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_mali/qeglfsmalimain.cpp +++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_mali/qeglfsmalimain.cpp @@ -48,7 +48,7 @@ class QEglFSMaliIntegrationPlugin : public QEglFSDeviceIntegrationPlugin Q_PLUGIN_METADATA(IID QEglFSDeviceIntegrationFactoryInterface_iid FILE "eglfs_mali.json") public: - QEglFSDeviceIntegration *create() Q_DECL_OVERRIDE { return new QEglFSMaliIntegration; } + QEglFSDeviceIntegration *create() override { return new QEglFSMaliIntegration; } }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_viv/qeglfsvivintegration.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_viv/qeglfsvivintegration.cpp index f2fcc0d3ff..763a4a462b 100644 --- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_viv/qeglfsvivintegration.cpp +++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_viv/qeglfsvivintegration.cpp @@ -63,9 +63,11 @@ void QEglFSVivIntegration::platformInit() #ifdef Q_OS_INTEGRITY VivanteInit(); + mNativeDisplay = fbGetDisplay(); +#else + mNativeDisplay = fbGetDisplayByIndex(framebufferIndex()); #endif - mNativeDisplay = fbGetDisplayByIndex(framebufferIndex()); fbGetDisplayGeometry(mNativeDisplay, &width, &height); mScreenSize.setHeight(height); mScreenSize.setWidth(width); diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_viv/qeglfsvivintegration.h b/src/plugins/platforms/eglfs/deviceintegration/eglfs_viv/qeglfsvivintegration.h index 2e98c2b4b1..4d1718afcf 100644 --- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_viv/qeglfsvivintegration.h +++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_viv/qeglfsvivintegration.h @@ -47,11 +47,11 @@ QT_BEGIN_NAMESPACE class QEglFSVivIntegration : public QEglFSDeviceIntegration { public: - void platformInit() Q_DECL_OVERRIDE; - QSize screenSize() const Q_DECL_OVERRIDE; - EGLNativeWindowType createNativeWindow(QPlatformWindow *window, const QSize &size, const QSurfaceFormat &format) Q_DECL_OVERRIDE; - void destroyNativeWindow(EGLNativeWindowType window) Q_DECL_OVERRIDE; - EGLNativeDisplayType platformDisplay() const Q_DECL_OVERRIDE; + 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; diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_viv/qeglfsvivmain.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_viv/qeglfsvivmain.cpp index ebe2091b1e..0736637b6b 100644 --- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_viv/qeglfsvivmain.cpp +++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_viv/qeglfsvivmain.cpp @@ -48,7 +48,7 @@ class QEglFSVivIntegrationPlugin : public QEglFSDeviceIntegrationPlugin Q_PLUGIN_METADATA(IID QEglFSDeviceIntegrationFactoryInterface_iid FILE "eglfs_viv.json") public: - QEglFSDeviceIntegration *create() Q_DECL_OVERRIDE { return new QEglFSVivIntegration; } + QEglFSDeviceIntegration *create() override { return new QEglFSVivIntegration; } }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_viv_wl/qeglfsvivwlintegration.h b/src/plugins/platforms/eglfs/deviceintegration/eglfs_viv_wl/qeglfsvivwlintegration.h index 9abbe817a6..2c49eb6440 100644 --- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_viv_wl/qeglfsvivwlintegration.h +++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_viv_wl/qeglfsvivwlintegration.h @@ -48,13 +48,13 @@ QT_BEGIN_NAMESPACE class QEglFSVivWaylandIntegration : public QEglFSDeviceIntegration { public: - void platformInit() Q_DECL_OVERRIDE; - QSize screenSize() const Q_DECL_OVERRIDE; - EGLNativeWindowType createNativeWindow(QPlatformWindow *window, const QSize &size, const QSurfaceFormat &format) Q_DECL_OVERRIDE; - void destroyNativeWindow(EGLNativeWindowType window) Q_DECL_OVERRIDE; - EGLNativeDisplayType platformDisplay() const Q_DECL_OVERRIDE; + 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; - void *wlDisplay() const Q_DECL_OVERRIDE; + void *wlDisplay() const override; private: QSize mScreenSize; EGLNativeDisplayType mNativeDisplay; diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_viv_wl/qeglfsvivwlmain.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_viv_wl/qeglfsvivwlmain.cpp index 3b26feda07..6cdc9346c0 100644 --- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_viv_wl/qeglfsvivwlmain.cpp +++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_viv_wl/qeglfsvivwlmain.cpp @@ -48,7 +48,7 @@ class QEglFSVivWaylandIntegrationPlugin : public QEglFSDeviceIntegrationPlugin Q_PLUGIN_METADATA(IID QEglFSDeviceIntegrationFactoryInterface_iid FILE "eglfs_viv_wl.json") public: - QEglFSDeviceIntegration *create() Q_DECL_OVERRIDE { return new QEglFSVivWaylandIntegration; } + QEglFSDeviceIntegration *create() override { return new QEglFSVivWaylandIntegration; } }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_x11/qeglfsx11integration.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_x11/qeglfsx11integration.cpp index 0a547b832f..64d0d9b515 100644 --- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_x11/qeglfsx11integration.cpp +++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_x11/qeglfsx11integration.cpp @@ -114,7 +114,7 @@ void EventReader::run() { Qt::MouseButtons buttons; - xcb_generic_event_t *event; + xcb_generic_event_t *event = nullptr; while (running.load() && (event = xcb_wait_for_event(m_integration->connection()))) { uint response_type = event->response_type & ~0x80; switch (response_type) { diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_x11/qeglfsx11integration.h b/src/plugins/platforms/eglfs/deviceintegration/eglfs_x11/qeglfsx11integration.h index c0f0ee5f22..bf431caaac 100644 --- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_x11/qeglfsx11integration.h +++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_x11/qeglfsx11integration.h @@ -69,15 +69,15 @@ class QEglFSX11Integration : public QEglFSDeviceIntegration public: QEglFSX11Integration() : m_connection(0), m_window(0), m_eventReader(0) {} - void platformInit() Q_DECL_OVERRIDE; - void platformDestroy() Q_DECL_OVERRIDE; - EGLNativeDisplayType platformDisplay() const Q_DECL_OVERRIDE; - QSize screenSize() const Q_DECL_OVERRIDE; + void platformInit() override; + void platformDestroy() override; + EGLNativeDisplayType platformDisplay() const override; + QSize screenSize() const override; EGLNativeWindowType createNativeWindow(QPlatformWindow *window, const QSize &size, - const QSurfaceFormat &format) Q_DECL_OVERRIDE; - void destroyNativeWindow(EGLNativeWindowType window) Q_DECL_OVERRIDE; - bool hasCapability(QPlatformIntegration::Capability cap) const Q_DECL_OVERRIDE; + const QSurfaceFormat &format) override; + void destroyNativeWindow(EGLNativeWindowType window) override; + bool hasCapability(QPlatformIntegration::Capability cap) const override; xcb_connection_t *connection() { return m_connection; } const xcb_atom_t *atoms() const { return m_atoms; } diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_x11/qeglfsx11main.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_x11/qeglfsx11main.cpp index c15e05b657..39ab54ae5a 100644 --- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_x11/qeglfsx11main.cpp +++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_x11/qeglfsx11main.cpp @@ -48,7 +48,7 @@ class QEglFSX11IntegrationPlugin : public QEglFSDeviceIntegrationPlugin Q_PLUGIN_METADATA(IID QEglFSDeviceIntegrationFactoryInterface_iid FILE "eglfs_x11.json") public: - QEglFSDeviceIntegration *create() Q_DECL_OVERRIDE { return new QEglFSX11Integration; } + QEglFSDeviceIntegration *create() override { return new QEglFSX11Integration; } }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/eglfs/eglfsdeviceintegration.pro b/src/plugins/platforms/eglfs/eglfsdeviceintegration.pro index 2593df937b..187cbc025f 100644 --- a/src/plugins/platforms/eglfs/eglfsdeviceintegration.pro +++ b/src/plugins/platforms/eglfs/eglfsdeviceintegration.pro @@ -12,11 +12,14 @@ QT += \ core-private gui-private \ devicediscovery_support-private eventdispatcher_support-private \ service_support-private theme_support-private fontdatabase_support-private \ - fb_support-private egl_support-private platformcompositor_support-private + fb_support-private egl_support-private qtHaveModule(input_support-private): \ QT += input_support-private +qtHaveModule(platformcompositor_support-private): \ + QT += platformcompositor_support-private + # Avoid X11 header collision, use generic EGL native types DEFINES += QT_EGL_NO_X11 diff --git a/src/plugins/platforms/eglfs/qeglfsmain.cpp b/src/plugins/platforms/eglfs/qeglfsmain.cpp index 2885d397c6..4f77b7cd17 100644 --- a/src/plugins/platforms/eglfs/qeglfsmain.cpp +++ b/src/plugins/platforms/eglfs/qeglfsmain.cpp @@ -47,7 +47,7 @@ class QEglFSIntegrationPlugin : public QPlatformIntegrationPlugin Q_OBJECT Q_PLUGIN_METADATA(IID QPlatformIntegrationFactoryInterface_iid FILE "eglfs.json") public: - QPlatformIntegration *create(const QString&, const QStringList&) Q_DECL_OVERRIDE; + QPlatformIntegration *create(const QString&, const QStringList&) override; }; QPlatformIntegration* QEglFSIntegrationPlugin::create(const QString& system, const QStringList& paramList) diff --git a/src/plugins/platforms/integrity/main.cpp b/src/plugins/platforms/integrity/main.cpp index 3330ddc5ae..f75e227335 100644 --- a/src/plugins/platforms/integrity/main.cpp +++ b/src/plugins/platforms/integrity/main.cpp @@ -1,31 +1,37 @@ /**************************************************************************** ** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ +** 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:LGPL21$ +** $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 http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. +** 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 2.1 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** 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. ** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** 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$ ** diff --git a/src/plugins/platforms/integrity/qintegrityfbintegration.cpp b/src/plugins/platforms/integrity/qintegrityfbintegration.cpp index a88c85e30d..ae802bb1fa 100644 --- a/src/plugins/platforms/integrity/qintegrityfbintegration.cpp +++ b/src/plugins/platforms/integrity/qintegrityfbintegration.cpp @@ -1,31 +1,37 @@ /**************************************************************************** ** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ +** 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:LGPL21$ +** $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 http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. +** 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 2.1 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** 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. ** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** 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$ ** diff --git a/src/plugins/platforms/integrity/qintegrityfbintegration.h b/src/plugins/platforms/integrity/qintegrityfbintegration.h index 3210cc9369..a954dc2356 100644 --- a/src/plugins/platforms/integrity/qintegrityfbintegration.h +++ b/src/plugins/platforms/integrity/qintegrityfbintegration.h @@ -1,31 +1,37 @@ /**************************************************************************** ** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ +** 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:LGPL21$ +** $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 http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. +** 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 2.1 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** 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. ** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** 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$ ** diff --git a/src/plugins/platforms/integrity/qintegrityfbscreen.cpp b/src/plugins/platforms/integrity/qintegrityfbscreen.cpp index 256cc117a2..3979937955 100644 --- a/src/plugins/platforms/integrity/qintegrityfbscreen.cpp +++ b/src/plugins/platforms/integrity/qintegrityfbscreen.cpp @@ -1,31 +1,37 @@ /**************************************************************************** ** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ +** 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:LGPL21$ +** $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 http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. +** 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 2.1 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** 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. ** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** 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$ ** @@ -206,7 +212,7 @@ QRegion QIntegrityFbScreen::doRedraw() (uint32_t)rects[i].width(), (uint32_t)rects[i].height() }; - mBlitter->drawImage(rects[i], *mScreenImage, rects[i]); + mBlitter->drawImage(rects[i], mScreenImage, rects[i]); gh_FB_expose(mFbh, &fbrect, NULL); } return touched; diff --git a/src/plugins/platforms/integrity/qintegrityfbscreen.h b/src/plugins/platforms/integrity/qintegrityfbscreen.h index 5b4d900a4b..6bc78913c9 100644 --- a/src/plugins/platforms/integrity/qintegrityfbscreen.h +++ b/src/plugins/platforms/integrity/qintegrityfbscreen.h @@ -1,31 +1,37 @@ /**************************************************************************** ** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ +** 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:LGPL21$ +** $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 http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. +** 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 2.1 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** 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. ** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** 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$ ** diff --git a/src/plugins/platforms/integrity/qintegrityhidmanager.cpp b/src/plugins/platforms/integrity/qintegrityhidmanager.cpp index 64eda98e2a..49583735f5 100644 --- a/src/plugins/platforms/integrity/qintegrityhidmanager.cpp +++ b/src/plugins/platforms/integrity/qintegrityhidmanager.cpp @@ -1,31 +1,37 @@ /**************************************************************************** ** ** Copyright (C) 2015 Green Hills Software -** Contact: http://www.qt.io/licensing/ +** Contact: https://www.qt.io/licensing/ ** -** This file is part of the QtGui module of the Qt Toolkit. +** This file is part of the plugins of the Qt Toolkit. ** -** $QT_BEGIN_LICENSE:LGPL21$ +** $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 http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. +** 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 2.1 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** 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. ** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** 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$ ** diff --git a/src/plugins/platforms/integrity/qintegrityhidmanager.h b/src/plugins/platforms/integrity/qintegrityhidmanager.h index 9a0f27d833..c8780b2dc2 100644 --- a/src/plugins/platforms/integrity/qintegrityhidmanager.h +++ b/src/plugins/platforms/integrity/qintegrityhidmanager.h @@ -1,31 +1,37 @@ /**************************************************************************** ** ** Copyright (C) 2015 Green Hills Software -** Contact: http://www.qt.io/licensing/ +** Contact: https://www.qt.io/licensing/ ** -** This file is part of the QtGui module of the Qt Toolkit. +** This file is part of the plugins of the Qt Toolkit. ** -** $QT_BEGIN_LICENSE:LGPL21$ +** $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 http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. +** 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 2.1 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** 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. ** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** 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$ ** diff --git a/src/plugins/platforms/ios/kernel.pro b/src/plugins/platforms/ios/kernel.pro index caafe89730..6eb9f2c534 100644 --- a/src/plugins/platforms/ios/kernel.pro +++ b/src/plugins/platforms/ios/kernel.pro @@ -1,5 +1,12 @@ TARGET = qios +# QTBUG-42937: Work around linker errors caused by circular +# dependencies between the iOS platform plugin and the user +# application's main() when the plugin is a shared library. +qtConfig(shared): CONFIG += static + +CONFIG += no_app_extension_api_only + QT += \ core-private gui-private \ clipboard_support-private fontdatabase_support-private graphics_support-private diff --git a/src/plugins/platforms/ios/optional/nsphotolibrarysupport/nsphotolibrarysupport.pro b/src/plugins/platforms/ios/optional/nsphotolibrarysupport/nsphotolibrarysupport.pro index f4588dda03..7379765599 100644 --- a/src/plugins/platforms/ios/optional/nsphotolibrarysupport/nsphotolibrarysupport.pro +++ b/src/plugins/platforms/ios/optional/nsphotolibrarysupport/nsphotolibrarysupport.pro @@ -1,7 +1,11 @@ TARGET = qiosnsphotolibrarysupport +# QTBUG-42937: Since the iOS plugin (kernel) is +# static, this plugin needs to be static as well. +qtConfig(shared): CONFIG += static + QT += core gui gui-private -LIBS += -framework UIKit -framework AssetsLibrary +LIBS += -framework Foundation -framework UIKit -framework AssetsLibrary HEADERS = \ qiosfileengineassetslibrary.h \ diff --git a/src/plugins/platforms/ios/optional/nsphotolibrarysupport/plugin.mm b/src/plugins/platforms/ios/optional/nsphotolibrarysupport/plugin.mm index 2ec0d33a41..8b372b8749 100644 --- a/src/plugins/platforms/ios/optional/nsphotolibrarysupport/plugin.mm +++ b/src/plugins/platforms/ios/optional/nsphotolibrarysupport/plugin.mm @@ -1,31 +1,37 @@ /**************************************************************************** ** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ +** 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:LGPL21$ +** $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 http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. +** 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 2.1 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** 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. ** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** 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$ ** diff --git a/src/plugins/platforms/ios/optional/nsphotolibrarysupport/qiosimagepickercontroller.h b/src/plugins/platforms/ios/optional/nsphotolibrarysupport/qiosimagepickercontroller.h index df3f6b9fa3..c52d498cd4 100644 --- a/src/plugins/platforms/ios/optional/nsphotolibrarysupport/qiosimagepickercontroller.h +++ b/src/plugins/platforms/ios/optional/nsphotolibrarysupport/qiosimagepickercontroller.h @@ -1,31 +1,37 @@ /**************************************************************************** ** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ +** 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:LGPL21$ +** $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 http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. +** 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 2.1 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** 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. ** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** 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$ ** diff --git a/src/plugins/platforms/ios/optional/nsphotolibrarysupport/qiosimagepickercontroller.mm b/src/plugins/platforms/ios/optional/nsphotolibrarysupport/qiosimagepickercontroller.mm index f9662b964a..78e0f00ab4 100644 --- a/src/plugins/platforms/ios/optional/nsphotolibrarysupport/qiosimagepickercontroller.mm +++ b/src/plugins/platforms/ios/optional/nsphotolibrarysupport/qiosimagepickercontroller.mm @@ -1,31 +1,37 @@ /**************************************************************************** ** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ +** 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:LGPL21$ +** $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 http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. +** 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 2.1 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** 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. ** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** 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$ ** diff --git a/src/plugins/platforms/ios/qiosbackingstore.mm b/src/plugins/platforms/ios/qiosbackingstore.mm index 076e34c1a5..96be28af81 100644 --- a/src/plugins/platforms/ios/qiosbackingstore.mm +++ b/src/plugins/platforms/ios/qiosbackingstore.mm @@ -122,7 +122,17 @@ QIOSBackingStore::QIOSBackingStore(QWindow *window) QIOSBackingStore::~QIOSBackingStore() { - delete m_context; + if (window()->surfaceType() == QSurface::RasterGLSurface) { + // We're using composeAndFlush from QPlatformBackingStore, which + // need to clean up any textures in its destructor, so make the + // context current and keep it alive until QPlatformBackingStore + // has cleaned up everything. + makeCurrent(); + m_context->deleteLater(); + } else { + delete m_context; + } + delete m_glDevice; } diff --git a/src/plugins/platforms/ios/qiosinputcontext.mm b/src/plugins/platforms/ios/qiosinputcontext.mm index 68088540c6..237077400b 100644 --- a/src/plugins/platforms/ios/qiosinputcontext.mm +++ b/src/plugins/platforms/ios/qiosinputcontext.mm @@ -498,15 +498,32 @@ void QIOSInputContext::scrollToCursor() return; } - const int margin = 20; - QRectF translatedCursorPos = qApp->inputMethod()->cursorRectangle(); - translatedCursorPos.translate(focusView().qwindow->geometry().topLeft()); - - qreal keyboardY = [rootView convertRect:m_keyboardState.keyboardEndRect fromView:nil].origin.y; - int statusBarY = qGuiApp->primaryScreen()->availableGeometry().y(); + QWindow *focusWindow = qApp->focusWindow(); + QRect cursorRect = qApp->inputMethod()->cursorRectangle().translated(focusWindow->geometry().topLeft()).toRect(); + if (cursorRect.isNull()) { + scroll(0); + return; + } - scroll((translatedCursorPos.bottomLeft().y() < keyboardY - margin) ? 0 - : qMin(rootView.bounds.size.height - keyboardY, translatedCursorPos.y() - statusBarY - margin)); + // 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 + // include the space taken by the status bar at the moment. + QRect screenGeometry = focusWindow->screen()->geometry(); + QRect keyboardGeometry = QRectF::fromCGRect(m_keyboardState.keyboardEndRect).toRect(); + QRect availableGeometry = (QRegion(screenGeometry) - keyboardGeometry).boundingRect(); + + if (!availableGeometry.contains(cursorRect, true)) { + qImDebug() << "cursor rect" << cursorRect << "not fully within" << availableGeometry; + int scrollToCenter = -(availableGeometry.center() - cursorRect.center()).y(); + int scrollToBottom = focusWindow->screen()->geometry().bottom() - availableGeometry.bottom(); + scroll(qMin(scrollToCenter, scrollToBottom)); + } else { + scroll(0); + } } void QIOSInputContext::scroll(int y) @@ -519,6 +536,8 @@ void QIOSInputContext::scroll(int y) if (CATransform3DEqualToTransform(translationTransform, rootView.layer.sublayerTransform)) return; + qImDebug() << "scrolling root view to y =" << -y; + QPointer<QIOSInputContext> self = this; [UIView animateWithDuration:m_keyboardState.animationDuration delay:0 options:(m_keyboardState.animationCurve << 16) | UIViewAnimationOptionBeginFromCurrentState @@ -631,11 +650,21 @@ void QIOSInputContext::focusWindowChanged(QWindow *focusWindow) */ void QIOSInputContext::update(Qt::InputMethodQueries updatedProperties) { + qImDebug() << "fw =" << qApp->focusWindow() << "fo =" << qApp->focusObject(); + + // Changes to the focus object should always result in a call to setFocusObject(), + // triggering a reset() which will update all the properties based on the new + // focus object. We try to detect code paths that fail this assertion and smooth + // over the situation by doing a manual update of the focus object. + if (qApp->focusObject() != m_imeState.focusObject && updatedProperties != Qt::ImQueryAll) { + qWarning() << "stale focus object" << m_imeState.focusObject << ", doing manual update"; + setFocusObject(qApp->focusObject()); + return; + } + // Mask for properties that we are interested in and see if any of them changed updatedProperties &= (Qt::ImEnabled | Qt::ImHints | Qt::ImQueryInput | Qt::ImEnterKeyType | Qt::ImPlatformData); - qImDebug() << "fw =" << qApp->focusWindow() << "fo =" << qApp->focusObject(); - // Perform update first, so we can trust the value of inputMethodAccepted() Qt::InputMethodQueries changedProperties = m_imeState.update(updatedProperties); diff --git a/src/plugins/platforms/ios/qiosintegration.mm b/src/plugins/platforms/ios/qiosintegration.mm index e5b4d6da85..fbf167b514 100644 --- a/src/plugins/platforms/ios/qiosintegration.mm +++ b/src/plugins/platforms/ios/qiosintegration.mm @@ -61,6 +61,7 @@ #include <QtFontDatabaseSupport/private/qcoretextfontdatabase_p.h> #include <QtClipboardSupport/private/qmacmime_p.h> #include <QDir> +#include <QOperatingSystemVersion> #import <AudioToolbox/AudioServices.h> @@ -119,7 +120,7 @@ QIOSIntegration::QIOSIntegration() m_touchDevice = new QTouchDevice; m_touchDevice->setType(QTouchDevice::TouchScreen); QTouchDevice::Capabilities touchCapabilities = QTouchDevice::Position | QTouchDevice::NormalizedPosition; - if (QSysInfo::MacintoshVersion >= QSysInfo::MV_IOS_9_0) { + if (QOperatingSystemVersion::current() >= QOperatingSystemVersion(QOperatingSystemVersion::IOS, 9)) { if (mainScreen.traitCollection.forceTouchCapability == UIForceTouchCapabilityAvailable) touchCapabilities |= QTouchDevice::Pressure; } diff --git a/src/plugins/platforms/ios/qiosmessagedialog.mm b/src/plugins/platforms/ios/qiosmessagedialog.mm index 50d5442f17..4f0c667861 100644 --- a/src/plugins/platforms/ios/qiosmessagedialog.mm +++ b/src/plugins/platforms/ios/qiosmessagedialog.mm @@ -39,6 +39,7 @@ #import <UIKit/UIKit.h> +#include <QtCore/qoperatingsystemversion.h> #include <QtGui/qwindow.h> #include <QtGui/private/qguiapplication_p.h> #include <qpa/qplatformtheme.h> @@ -109,7 +110,7 @@ bool QIOSMessageDialog::show(Qt::WindowFlags windowFlags, Qt::WindowModality win if (m_alertController // Ensure that the dialog is not showing already || !options() // Some message dialogs don't have options (QErrorMessage) || windowModality == Qt::NonModal // We can only do modal dialogs - || QSysInfo::MacintoshVersion < QSysInfo::MV_IOS_8_0) // API limitation + || QOperatingSystemVersion::current() < QOperatingSystemVersion(QOperatingSystemVersion::IOS, 8)) // API limitation return false; m_alertController = [[UIAlertController diff --git a/src/plugins/platforms/ios/qiosoptionalplugininterface.h b/src/plugins/platforms/ios/qiosoptionalplugininterface.h index bcb8978e02..3f74e41c83 100644 --- a/src/plugins/platforms/ios/qiosoptionalplugininterface.h +++ b/src/plugins/platforms/ios/qiosoptionalplugininterface.h @@ -1,31 +1,37 @@ /**************************************************************************** ** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ +** 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:LGPL21$ +** $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 http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. +** 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 2.1 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** 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. ** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** 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$ ** diff --git a/src/plugins/platforms/ios/qiosscreen.mm b/src/plugins/platforms/ios/qiosscreen.mm index c518f9111d..3514bf63bb 100644 --- a/src/plugins/platforms/ios/qiosscreen.mm +++ b/src/plugins/platforms/ios/qiosscreen.mm @@ -45,6 +45,7 @@ #include "qiosapplicationdelegate.h" #include "qiosviewcontroller.h" #include "quiview.h" +#include <QtCore/qoperatingsystemversion.h> #include <QtGui/private/qwindow_p.h> #include <private/qcoregraphics_p.h> @@ -274,7 +275,7 @@ void QIOSScreen::updateProperties() if (m_uiScreen == [UIScreen mainScreen]) { Qt::ScreenOrientation statusBarOrientation = toQtScreenOrientation(UIDeviceOrientation([UIApplication sharedApplication].statusBarOrientation)); - if (QSysInfo::MacintoshVersion < QSysInfo::MV_IOS_8_0) { + if (QOperatingSystemVersion::current() < QOperatingSystemVersion(QOperatingSystemVersion::IOS, 8)) { // On iOS < 8.0 the UIScreen geometry is always in portait, and the system applies // the screen rotation to the root view-controller's view instead of directly to the // screen, like iOS 8 and above does. @@ -302,7 +303,7 @@ void QIOSScreen::updateProperties() if (m_geometry != previousGeometry) { QRectF physicalGeometry; - if (QSysInfo::MacintoshVersion >= QSysInfo::MV_IOS_8_0) { + if (QOperatingSystemVersion::current() >= QOperatingSystemVersion(QOperatingSystemVersion::IOS, 8)) { // We can't use the primaryOrientation of screen(), as we haven't reported the new geometry yet Qt::ScreenOrientation primaryOrientation = m_geometry.width() >= m_geometry.height() ? Qt::LandscapeOrientation : Qt::PortraitOrientation; @@ -406,10 +407,11 @@ qreal QIOSScreen::devicePixelRatio() const Qt::ScreenOrientation QIOSScreen::nativeOrientation() const { CGRect nativeBounds = -#if !defined(Q_OS_TVOS) && QT_IOS_PLATFORM_SDK_EQUAL_OR_ABOVE(__IPHONE_8_0) - QSysInfo::MacintoshVersion >= QSysInfo::MV_IOS_8_0 ? m_uiScreen.nativeBounds : -#endif +#if defined(Q_OS_IOS) + m_uiScreen.nativeBounds; +#else m_uiScreen.bounds; +#endif // All known iOS devices have a native orientation of portrait, but to // be on the safe side we compare the width and height of the bounds. diff --git a/src/plugins/platforms/ios/qiostextinputoverlay.h b/src/plugins/platforms/ios/qiostextinputoverlay.h index 2f01993b19..9ed3a9b271 100644 --- a/src/plugins/platforms/ios/qiostextinputoverlay.h +++ b/src/plugins/platforms/ios/qiostextinputoverlay.h @@ -1,31 +1,37 @@ /**************************************************************************** ** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ +** 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:LGPL21$ +** $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 http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. +** 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 2.1 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** 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. ** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** 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$ ** diff --git a/src/plugins/platforms/ios/qiostextinputoverlay.mm b/src/plugins/platforms/ios/qiostextinputoverlay.mm index 238d7addf6..9b97ce17bb 100644 --- a/src/plugins/platforms/ios/qiostextinputoverlay.mm +++ b/src/plugins/platforms/ios/qiostextinputoverlay.mm @@ -1,31 +1,37 @@ /**************************************************************************** ** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ +** 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:LGPL21$ +** $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 http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. +** 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 2.1 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** 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. ** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** 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$ ** @@ -110,6 +116,11 @@ static void executeBlockWithoutAnimation(Block block) dispatch_async(dispatch_get_main_queue (), ^{ self.visible = YES; }); } }]; + [center addObserverForName:UIKeyboardDidHideNotification object:nil queue:nil + usingBlock:^(NSNotification *) { + self.visible = NO; + }]; + } return self; @@ -219,7 +230,7 @@ static void executeBlockWithoutAnimation(Block block) borderLayer.borderColor = [[UIColor lightGrayColor] CGColor]; [self addSublayer:borderLayer]; - if (QSysInfo::MacintoshVersion < QSysInfo::MV_IOS_7_0) { + if (QOperatingSystemVersion::current() < QOperatingSystemVersion(QOperatingSystemVersion::IOS, 7)) { // [UIView snapshotViewAfterScreenUpdates:] is available since iOS 7.0. // Just silently ignore showing the loupe for older versions. self.hidden = YES; @@ -267,7 +278,7 @@ static void executeBlockWithoutAnimation(Block block) - (void)display { - if (QSysInfo::MacintoshVersion < QSysInfo::MV_IOS_7_0) + if (QOperatingSystemVersion::current() < QOperatingSystemVersion(QOperatingSystemVersion::IOS, 7)) return; // Take a snapshow of the target view, magnify the area around the focal diff --git a/src/plugins/platforms/ios/quiview.mm b/src/plugins/platforms/ios/quiview.mm index 2a1444e9e5..9966bd50a3 100644 --- a/src/plugins/platforms/ios/quiview.mm +++ b/src/plugins/platforms/ios/quiview.mm @@ -48,6 +48,7 @@ #include "qiosmenu.h" #endif +#include <QtCore/qoperatingsystemversion.h> #include <QtGui/private/qguiapplication_p.h> #include <QtGui/private/qwindow_p.h> #include <qpa/qwindowsysteminterface_p.h> @@ -208,18 +209,23 @@ - (BOOL)becomeFirstResponder { - FirstResponderCandidate firstResponderCandidate(self); + { + // Scope for the duration of becoming first responder only, as the window + // activation event may trigger new responders, which we don't want to be + // blocked by this guard. + FirstResponderCandidate firstResponderCandidate(self); - qImDebug() << "win:" << m_qioswindow->window() << "self:" << self - << "first:" << [UIResponder currentFirstResponder]; + qImDebug() << "win:" << m_qioswindow->window() << "self:" << self + << "first:" << [UIResponder currentFirstResponder]; - if (![super becomeFirstResponder]) { - qImDebug() << m_qioswindow->window() - << "was not allowed to become first responder"; - return NO; - } + if (![super becomeFirstResponder]) { + qImDebug() << m_qioswindow->window() + << "was not allowed to become first responder"; + return NO; + } - qImDebug() << m_qioswindow->window() << "became first responder"; + qImDebug() << m_qioswindow->window() << "became first responder"; + } if (qGuiApp->focusWindow() != m_qioswindow->window()) QWindowSystemInterface::handleWindowActivated<QWindowSystemInterface::SynchronousDelivery>(m_qioswindow->window()); @@ -291,7 +297,7 @@ QTouchDevice *touchDevice = QIOSIntegration::instance()->touchDevice(); QTouchDevice::Capabilities touchCapabilities = touchDevice->capabilities(); - if (QSysInfo::MacintoshVersion >= QSysInfo::MV_IOS_9_0) { + if (QOperatingSystemVersion::current() >= QOperatingSystemVersion(QOperatingSystemVersion::IOS, 9)) { if (self.traitCollection.forceTouchCapability == UIForceTouchCapabilityAvailable) touchCapabilities |= QTouchDevice::Pressure; else diff --git a/src/plugins/platforms/linuxfb/linuxfb.pro b/src/plugins/platforms/linuxfb/linuxfb.pro index e2fa31211d..d3a4476f80 100644 --- a/src/plugins/platforms/linuxfb/linuxfb.pro +++ b/src/plugins/platforms/linuxfb/linuxfb.pro @@ -10,8 +10,18 @@ QT += \ qtHaveModule(input_support-private): \ QT += input_support-private -SOURCES = main.cpp qlinuxfbintegration.cpp qlinuxfbscreen.cpp -HEADERS = qlinuxfbintegration.h qlinuxfbscreen.h +SOURCES = main.cpp \ + qlinuxfbintegration.cpp \ + qlinuxfbscreen.cpp + +HEADERS = qlinuxfbintegration.h \ + qlinuxfbscreen.h + +qtHaveModule(kms_support-private) { + QT += kms_support-private + SOURCES += qlinuxfbdrmscreen.cpp + HEADERS += qlinuxfbdrmscreen.h +} OTHER_FILES += linuxfb.json diff --git a/src/plugins/platforms/linuxfb/qlinuxfbdrmscreen.cpp b/src/plugins/platforms/linuxfb/qlinuxfbdrmscreen.cpp new file mode 100644 index 0000000000..2ca251c4af --- /dev/null +++ b/src/plugins/platforms/linuxfb/qlinuxfbdrmscreen.cpp @@ -0,0 +1,412 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +// Experimental DRM dumb buffer backend. +// +// TODO: +// Multiscreen: QWindow-QScreen(-output) association. Needs some reorg (device cannot be owned by screen) +// Find card via devicediscovery like in eglfs_kms. +// Mode restore like QEglFSKmsInterruptHandler. +// Formats other then 32 bpp? +// grabWindow + +#include "qlinuxfbdrmscreen.h" +#include <QLoggingCategory> +#include <QGuiApplication> +#include <QPainter> +#include <QtFbSupport/private/qfbcursor_p.h> +#include <QtFbSupport/private/qfbwindow_p.h> +#include <QtKmsSupport/private/qkmsdevice_p.h> +#include <QtCore/private/qcore_unix_p.h> +#include <sys/mman.h> + +QT_BEGIN_NAMESPACE + +Q_LOGGING_CATEGORY(qLcFbDrm, "qt.qpa.fb") + +static const int BUFFER_COUNT = 2; + +class QLinuxFbDevice : public QKmsDevice +{ +public: + struct Framebuffer { + Framebuffer() : handle(0), pitch(0), size(0), fb(0), p(MAP_FAILED) { } + uint32_t handle; + uint32_t pitch; + uint64_t size; + uint32_t fb; + void *p; + QImage wrapper; + }; + + struct Output { + Output() : backFb(0), flipped(false) { } + QKmsOutput kmsOutput; + Framebuffer fb[BUFFER_COUNT]; + QRegion dirty[BUFFER_COUNT]; + int backFb; + bool flipped; + QSize currentRes() const { + const drmModeModeInfo &modeInfo(kmsOutput.modes[kmsOutput.mode]); + return QSize(modeInfo.hdisplay, modeInfo.vdisplay); + } + }; + + QLinuxFbDevice(QKmsScreenConfig *screenConfig); + + bool open() override; + void close() override; + + void createFramebuffers(); + void destroyFramebuffers(); + void setMode(); + + void swapBuffers(Output *output); + + int outputCount() const { return m_outputs.count(); } + Output *output(int idx) { return &m_outputs[idx]; } + +private: + void *nativeDisplay() const override; + QPlatformScreen *createScreen(const QKmsOutput &output) override; + void registerScreen(QPlatformScreen *screen, + bool isPrimary, + const QPoint &virtualPos, + const QList<QPlatformScreen *> &virtualSiblings) override; + + bool createFramebuffer(Output *output, int bufferIdx); + void destroyFramebuffer(Output *output, int bufferIdx); + + static void pageFlipHandler(int fd, unsigned int sequence, + unsigned int tv_sec, unsigned int tv_usec, void *user_data); + + QVector<Output> m_outputs; +}; + +QLinuxFbDevice::QLinuxFbDevice(QKmsScreenConfig *screenConfig) + : QKmsDevice(screenConfig, QStringLiteral("/dev/dri/card0")) +{ +} + +bool QLinuxFbDevice::open() +{ + int fd = qt_safe_open(devicePath().toLocal8Bit().constData(), O_RDWR | O_CLOEXEC); + if (fd == -1) { + qErrnoWarning("Could not open DRM device %s", qPrintable(devicePath())); + return false; + } + + uint64_t hasDumbBuf = 0; + if (drmGetCap(fd, DRM_CAP_DUMB_BUFFER, &hasDumbBuf) == -1 || !hasDumbBuf) { + qWarning("Dumb buffers not supported"); + qt_safe_close(fd); + return false; + } + + setFd(fd); + + qCDebug(qLcFbDrm, "DRM device %s opened", qPrintable(devicePath())); + + return true; +} + +void QLinuxFbDevice::close() +{ + for (Output &output : m_outputs) + output.kmsOutput.cleanup(this); // restore mode + + m_outputs.clear(); + + if (fd() != -1) { + qCDebug(qLcFbDrm, "Closing DRM device"); + qt_safe_close(fd()); + setFd(-1); + } +} + +void *QLinuxFbDevice::nativeDisplay() const +{ + Q_UNREACHABLE(); + return nullptr; +} + +QPlatformScreen *QLinuxFbDevice::createScreen(const QKmsOutput &output) +{ + qCDebug(qLcFbDrm, "Got a new output: %s", qPrintable(output.name)); + Output o; + o.kmsOutput = output; + m_outputs.append(o); + return nullptr; // no platformscreen, we are not a platform plugin +} + +void QLinuxFbDevice::registerScreen(QPlatformScreen *screen, + bool isPrimary, + const QPoint &virtualPos, + const QList<QPlatformScreen *> &virtualSiblings) +{ + Q_UNUSED(screen); + Q_UNUSED(isPrimary); + Q_UNUSED(virtualPos); + Q_UNUSED(virtualSiblings); + Q_UNREACHABLE(); +} + +bool QLinuxFbDevice::createFramebuffer(QLinuxFbDevice::Output *output, int bufferIdx) +{ + const QSize size = output->currentRes(); + const uint32_t w = size.width(); + const uint32_t h = size.height(); + drm_mode_create_dumb creq = { + h, + w, + 32, + 0, 0, 0, 0 + }; + if (drmIoctl(fd(), DRM_IOCTL_MODE_CREATE_DUMB, &creq) == -1) { + qErrnoWarning(errno, "Failed to create dumb buffer"); + return false; + } + + Framebuffer &fb(output->fb[bufferIdx]); + fb.handle = creq.handle; + fb.pitch = creq.pitch; + fb.size = creq.size; + qCDebug(qLcFbDrm, "Got a dumb buffer for size %dx%d, handle %u, pitch %u, size %u", + w, h, fb.handle, fb.pitch, (uint) fb.size); + + if (drmModeAddFB(fd(), w, h, 24, 32, fb.pitch, fb.handle, &fb.fb) == -1) { + qErrnoWarning(errno, "Failed to add FB"); + return false; + } + + drm_mode_map_dumb mreq = { + fb.handle, + 0, 0 + }; + if (drmIoctl(fd(), DRM_IOCTL_MODE_MAP_DUMB, &mreq) == -1) { + qErrnoWarning(errno, "Failed to map dumb buffer"); + return false; + } + fb.p = mmap(0, fb.size, PROT_READ | PROT_WRITE, MAP_SHARED, fd(), mreq.offset); + if (fb.p == MAP_FAILED) { + qErrnoWarning(errno, "Failed to mmap dumb buffer"); + return false; + } + + qCDebug(qLcFbDrm, "FB is %u, mapped at %p", fb.fb, fb.p); + memset(fb.p, 0, fb.size); + + fb.wrapper = QImage(static_cast<uchar *>(fb.p), w, h, fb.pitch, QImage::Format_ARGB32); + + return true; +} + +void QLinuxFbDevice::createFramebuffers() +{ + for (Output &output : m_outputs) { + for (int i = 0; i < BUFFER_COUNT; ++i) { + if (!createFramebuffer(&output, i)) + return; + } + output.backFb = 0; + output.flipped = false; + } +} + +void QLinuxFbDevice::destroyFramebuffer(QLinuxFbDevice::Output *output, int bufferIdx) +{ + Framebuffer &fb(output->fb[bufferIdx]); + if (fb.p != MAP_FAILED) + munmap(fb.p, fb.size); + if (fb.fb) { + if (drmModeRmFB(fd(), fb.fb) == -1) + qErrnoWarning("Failed to remove fb"); + } + if (fb.handle) { + drm_mode_destroy_dumb dreq = { fb.handle }; + if (drmIoctl(fd(), DRM_IOCTL_MODE_DESTROY_DUMB, &dreq) == -1) + qErrnoWarning(errno, "Failed to destroy dumb buffer %u", fb.handle); + } + fb = Framebuffer(); +} + +void QLinuxFbDevice::destroyFramebuffers() +{ + for (Output &output : m_outputs) { + for (int i = 0; i < BUFFER_COUNT; ++i) + destroyFramebuffer(&output, i); + } +} + +void QLinuxFbDevice::setMode() +{ + for (Output &output : m_outputs) { + drmModeModeInfo &modeInfo(output.kmsOutput.modes[output.kmsOutput.mode]); + if (drmModeSetCrtc(fd(), output.kmsOutput.crtc_id, output.fb[0].fb, 0, 0, + &output.kmsOutput.connector_id, 1, &modeInfo) == -1) { + qErrnoWarning(errno, "Failed to set mode"); + return; + } + + output.kmsOutput.mode_set = true; // have cleanup() to restore the mode + output.kmsOutput.setPowerState(this, QPlatformScreen::PowerStateOn); + } +} + +void QLinuxFbDevice::pageFlipHandler(int fd, unsigned int sequence, + unsigned int tv_sec, unsigned int tv_usec, + void *user_data) +{ + Q_UNUSED(fd); + Q_UNUSED(sequence); + Q_UNUSED(tv_sec); + Q_UNUSED(tv_usec); + + Output *output = static_cast<Output *>(user_data); + output->backFb = (output->backFb + 1) % BUFFER_COUNT; +} + +void QLinuxFbDevice::swapBuffers(Output *output) +{ + Framebuffer &fb(output->fb[output->backFb]); + if (drmModePageFlip(fd(), output->kmsOutput.crtc_id, fb.fb, DRM_MODE_PAGE_FLIP_EVENT, output) == -1) { + qErrnoWarning(errno, "Page flip failed"); + return; + } + + const int fbIdx = output->backFb; + while (output->backFb == fbIdx) { + drmEventContext drmEvent = { + DRM_EVENT_CONTEXT_VERSION, + nullptr, + pageFlipHandler + }; + // Blocks until there is something to read on the drm fd + // and calls back pageFlipHandler once the flip completes. + drmHandleEvent(fd(), &drmEvent); + } +} + +QLinuxFbDrmScreen::QLinuxFbDrmScreen(const QStringList &args) + : m_screenConfig(nullptr), + m_device(nullptr) +{ + Q_UNUSED(args); +} + +QLinuxFbDrmScreen::~QLinuxFbDrmScreen() +{ + if (m_device) { + m_device->destroyFramebuffers(); + m_device->close(); + delete m_device; + } + delete m_screenConfig; +} + +bool QLinuxFbDrmScreen::initialize() +{ + m_screenConfig = new QKmsScreenConfig; + m_device = new QLinuxFbDevice(m_screenConfig); + if (!m_device->open()) + return false; + + // Discover outputs. Calls back Device::createScreen(). + m_device->createScreens(); + // Now off to dumb buffer specifics. + m_device->createFramebuffers(); + // Do the modesetting. + m_device->setMode(); + + QLinuxFbDevice::Output *output(m_device->output(0)); + + mGeometry = QRect(QPoint(0, 0), output->currentRes()); + mDepth = 32; + mFormat = QImage::Format_ARGB32; + mPhysicalSize = output->kmsOutput.physical_size; + qCDebug(qLcFbDrm) << mGeometry << mPhysicalSize; + + QFbScreen::initializeCompositor(); + + mCursor = new QFbCursor(this); + + return true; +} + +QRegion QLinuxFbDrmScreen::doRedraw() +{ + const QRegion dirty = QFbScreen::doRedraw(); + if (dirty.isEmpty()) + return dirty; + + QLinuxFbDevice::Output *output(m_device->output(0)); + + for (int i = 0; i < BUFFER_COUNT; ++i) + output->dirty[i] += dirty; + + if (output->fb[output->backFb].wrapper.isNull()) + return dirty; + + QPainter pntr(&output->fb[output->backFb].wrapper); + // Image has alpha but no need for blending at this stage. + // Do not waste time with the default SourceOver. + pntr.setCompositionMode(QPainter::CompositionMode_Source); + for (const QRect &rect : qAsConst(output->dirty[output->backFb])) + pntr.drawImage(rect, mScreenImage, rect); + pntr.end(); + + output->dirty[output->backFb] = QRegion(); + + m_device->swapBuffers(output); + + return dirty; +} + +QPixmap QLinuxFbDrmScreen::grabWindow(WId wid, int x, int y, int width, int height) const +{ + Q_UNUSED(wid); + Q_UNUSED(x); + Q_UNUSED(y); + Q_UNUSED(width); + Q_UNUSED(height); + + return QPixmap(); +} + +QT_END_NAMESPACE diff --git a/src/plugins/platforms/linuxfb/qlinuxfbdrmscreen.h b/src/plugins/platforms/linuxfb/qlinuxfbdrmscreen.h new file mode 100644 index 0000000000..50a9576798 --- /dev/null +++ b/src/plugins/platforms/linuxfb/qlinuxfbdrmscreen.h @@ -0,0 +1,68 @@ +/**************************************************************************** +** +** 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 QLINUXFBDRMSCREEN_H +#define QLINUXFBDRMSCREEN_H + +#include <QtFbSupport/private/qfbscreen_p.h> + +QT_BEGIN_NAMESPACE + +class QKmsScreenConfig; +class QLinuxFbDevice; + +class QLinuxFbDrmScreen : public QFbScreen +{ + Q_OBJECT +public: + QLinuxFbDrmScreen(const QStringList &args); + ~QLinuxFbDrmScreen(); + + bool initialize() override; + QRegion doRedraw() override; + QPixmap grabWindow(WId wid, int x, int y, int width, int height) const override; + +private: + QKmsScreenConfig *m_screenConfig; + QLinuxFbDevice *m_device; +}; + +QT_END_NAMESPACE + +#endif // QLINUXFBDRMSCREEN_H diff --git a/src/plugins/platforms/linuxfb/qlinuxfbintegration.cpp b/src/plugins/platforms/linuxfb/qlinuxfbintegration.cpp index c1c235588e..ce193bdf90 100644 --- a/src/plugins/platforms/linuxfb/qlinuxfbintegration.cpp +++ b/src/plugins/platforms/linuxfb/qlinuxfbintegration.cpp @@ -39,6 +39,9 @@ #include "qlinuxfbintegration.h" #include "qlinuxfbscreen.h" +#if QT_CONFIG(kms) +#include "qlinuxfbdrmscreen.h" +#endif #include <QtFontDatabaseSupport/private/qgenericunixfontdatabase_p.h> #include <QtServiceSupport/private/qgenericunixservices_p.h> @@ -69,10 +72,16 @@ QT_BEGIN_NAMESPACE QLinuxFbIntegration::QLinuxFbIntegration(const QStringList ¶mList) - : m_fontDb(new QGenericUnixFontDatabase), + : m_primaryScreen(nullptr), + m_fontDb(new QGenericUnixFontDatabase), m_services(new QGenericUnixServices) { - m_primaryScreen = new QLinuxFbScreen(paramList); +#if QT_CONFIG(kms) + if (qEnvironmentVariableIntValue("QT_QPA_FB_DRM") != 0) + m_primaryScreen = new QLinuxFbDrmScreen(paramList); +#endif + if (!m_primaryScreen) + m_primaryScreen = new QLinuxFbScreen(paramList); } QLinuxFbIntegration::~QLinuxFbIntegration() diff --git a/src/plugins/platforms/linuxfb/qlinuxfbintegration.h b/src/plugins/platforms/linuxfb/qlinuxfbintegration.h index e48a1bae28..9934a8cd54 100644 --- a/src/plugins/platforms/linuxfb/qlinuxfbintegration.h +++ b/src/plugins/platforms/linuxfb/qlinuxfbintegration.h @@ -46,7 +46,7 @@ QT_BEGIN_NAMESPACE class QAbstractEventDispatcher; -class QLinuxFbScreen; +class QFbScreen; class QFbVtHandler; class QLinuxFbIntegration : public QPlatformIntegration, public QPlatformNativeInterface @@ -74,7 +74,7 @@ public: private: void createInputHandlers(); - QLinuxFbScreen *m_primaryScreen; + QFbScreen *m_primaryScreen; QPlatformInputContext *m_inputContext; QScopedPointer<QPlatformFontDatabase> m_fontDb; QScopedPointer<QPlatformServices> m_services; diff --git a/src/plugins/platforms/linuxfb/qlinuxfbscreen.cpp b/src/plugins/platforms/linuxfb/qlinuxfbscreen.cpp index 246c959fd3..dc7ea08dc5 100644 --- a/src/plugins/platforms/linuxfb/qlinuxfbscreen.cpp +++ b/src/plugins/platforms/linuxfb/qlinuxfbscreen.cpp @@ -414,7 +414,7 @@ QRegion QLinuxFbScreen::doRedraw() mBlitter->setCompositionMode(QPainter::CompositionMode_Source); for (const QRect &rect : touched) - mBlitter->drawImage(rect, *mScreenImage, rect); + mBlitter->drawImage(rect, mScreenImage, rect); return touched; } diff --git a/src/plugins/platforms/linuxfb/qlinuxfbscreen.h b/src/plugins/platforms/linuxfb/qlinuxfbscreen.h index 1e98191569..c7ce455e6a 100644 --- a/src/plugins/platforms/linuxfb/qlinuxfbscreen.h +++ b/src/plugins/platforms/linuxfb/qlinuxfbscreen.h @@ -54,11 +54,11 @@ public: QLinuxFbScreen(const QStringList &args); ~QLinuxFbScreen(); - bool initialize(); + bool initialize() override; - QPixmap grabWindow(WId wid, int x, int y, int width, int height) const Q_DECL_OVERRIDE; + QPixmap grabWindow(WId wid, int x, int y, int width, int height) const override; - QRegion doRedraw() Q_DECL_OVERRIDE; + QRegion doRedraw() override; private: QStringList mArgs; diff --git a/src/plugins/platforms/minimal/qminimalintegration.cpp b/src/plugins/platforms/minimal/qminimalintegration.cpp index 03c72502cb..aa0037f187 100644 --- a/src/plugins/platforms/minimal/qminimalintegration.cpp +++ b/src/plugins/platforms/minimal/qminimalintegration.cpp @@ -44,12 +44,19 @@ #include <QtGui/private/qguiapplication_p.h> #include <qpa/qplatformwindow.h> -#if defined(Q_OS_WIN) #include <QtFontDatabaseSupport/private/qbasicfontdatabase_p.h> +#if defined(Q_OS_WINRT) +# include <QtFontDatabaseSupport/private/qwinrtfontdatabase_p.h> +#elif defined(Q_OS_WIN) +# include <QtFontDatabaseSupport/private/qwindowsfontdatabase_p.h> +# if QT_CONFIG(freetype) +# include <QtFontDatabaseSupport/private/qwindowsfontdatabase_ft_p.h> +# endif +#elif defined(Q_OS_DARWIN) +# include <QtFontDatabaseSupport/private/qcoretextfontdatabase_p.h> #elif QT_CONFIG(fontconfig) -#include <QtFontDatabaseSupport/private/qgenericunixfontdatabase_p.h> -#else -#include <qpa/qplatformfontdatabase.h> +# include <QtFontDatabaseSupport/private/qgenericunixfontdatabase_p.h> +# include <qpa/qplatformfontdatabase.h> #endif #if !defined(Q_OS_WIN) @@ -70,6 +77,8 @@ static inline unsigned parseOptions(const QStringList ¶mList) for (const QString ¶m : paramList) { if (param == QLatin1String("enable_fonts")) options |= QMinimalIntegration::EnableFonts; + else if (param == QLatin1String("freetype")) + options |= QMinimalIntegration::FreeTypeFontDatabase; } return options; } @@ -117,12 +126,23 @@ public: QPlatformFontDatabase *QMinimalIntegration::fontDatabase() const { - if (m_options & EnableFonts) { + if (!m_fontDatabase && (m_options & EnableFonts)) { #if QT_CONFIG(fontconfig) - if (!m_fontDatabase) - m_fontDatabase = new QGenericUnixFontDatabase; + m_fontDatabase = new QGenericUnixFontDatabase; +#elif defined(Q_OS_WINRT) + m_fontDatabase = new QWinRTFontDatabase; +#elif defined(Q_OS_WIN) + if (m_options & FreeTypeFontDatabase) { +# if QT_CONFIG(freetype) + m_fontDatabase = new QWindowsFontDatabaseFT; +# endif // freetype + } else { + m_fontDatabase = new QWindowsFontDatabase; + } +#elif defined(Q_OS_DARWIN) + m_fontDatabase = new QCoreTextFontDatabase; #else - return QPlatformIntegration::fontDatabase(); + m_fontDatabase = QPlatformIntegration::fontDatabase(); #endif } if (!m_fontDatabase) diff --git a/src/plugins/platforms/minimal/qminimalintegration.h b/src/plugins/platforms/minimal/qminimalintegration.h index 755664d14d..eaa2f228c5 100644 --- a/src/plugins/platforms/minimal/qminimalintegration.h +++ b/src/plugins/platforms/minimal/qminimalintegration.h @@ -67,7 +67,8 @@ class QMinimalIntegration : public QPlatformIntegration public: enum Options { // Options to be passed on command line or determined from environment DebugBackingStore = 0x1, - EnableFonts = 0x2 + EnableFonts = 0x2, + FreeTypeFontDatabase = 0x4 }; explicit QMinimalIntegration(const QStringList ¶meters); diff --git a/src/plugins/platforms/minimalegl/minimalegl.pro b/src/plugins/platforms/minimalegl/minimalegl.pro index 88466e7f36..b7dde9069f 100644 --- a/src/plugins/platforms/minimalegl/minimalegl.pro +++ b/src/plugins/platforms/minimalegl/minimalegl.pro @@ -14,14 +14,17 @@ DEFINES += QT_EGL_NO_X11 SOURCES = main.cpp \ qminimaleglintegration.cpp \ qminimaleglwindow.cpp \ - qminimaleglbackingstore.cpp \ qminimaleglscreen.cpp HEADERS = qminimaleglintegration.h \ qminimaleglwindow.h \ - qminimaleglbackingstore.h \ qminimaleglscreen.h +qtConfig(opengl) { + SOURCES += qminimaleglbackingstore.cpp + HEADERS += qminimaleglbackingstore.h +} + CONFIG += egl OTHER_FILES += \ diff --git a/src/plugins/platforms/minimalegl/qminimaleglintegration.cpp b/src/plugins/platforms/minimalegl/qminimaleglintegration.cpp index c564e1e431..81512b1561 100644 --- a/src/plugins/platforms/minimalegl/qminimaleglintegration.cpp +++ b/src/plugins/platforms/minimalegl/qminimaleglintegration.cpp @@ -40,8 +40,9 @@ #include "qminimaleglintegration.h" #include "qminimaleglwindow.h" -#include "qminimaleglbackingstore.h" - +#ifndef QT_NO_OPENGL +# include "qminimaleglbackingstore.h" +#endif #include <QtFontDatabaseSupport/private/qgenericunixfontdatabase_p.h> #if defined(Q_OS_UNIX) @@ -127,13 +128,18 @@ QPlatformBackingStore *QMinimalEglIntegration::createPlatformBackingStore(QWindo #ifdef QEGL_EXTRA_DEBUG qWarning("QMinimalEglIntegration::createWindowSurface %p\n", window); #endif +#ifndef QT_NO_OPENGL return new QMinimalEglBackingStore(window); +#else + return nullptr; +#endif } - +#ifndef QT_NO_OPENGL QPlatformOpenGLContext *QMinimalEglIntegration::createPlatformOpenGLContext(QOpenGLContext *context) const { return static_cast<QMinimalEglScreen *>(context->screen()->handle())->platformContext(); } +#endif QPlatformFontDatabase *QMinimalEglIntegration::fontDatabase() const { diff --git a/src/plugins/platforms/minimalegl/qminimaleglintegration.h b/src/plugins/platforms/minimalegl/qminimaleglintegration.h index 529e89f85a..d0ab75bd3c 100644 --- a/src/plugins/platforms/minimalegl/qminimaleglintegration.h +++ b/src/plugins/platforms/minimalegl/qminimaleglintegration.h @@ -55,8 +55,9 @@ public: QPlatformWindow *createPlatformWindow(QWindow *window) const Q_DECL_OVERRIDE; QPlatformBackingStore *createPlatformBackingStore(QWindow *window) const Q_DECL_OVERRIDE; +#ifndef QT_NO_OPENGL QPlatformOpenGLContext *createPlatformOpenGLContext(QOpenGLContext *context) const Q_DECL_OVERRIDE; - +#endif QPlatformFontDatabase *fontDatabase() const Q_DECL_OVERRIDE; QAbstractEventDispatcher *createEventDispatcher() const Q_DECL_OVERRIDE; diff --git a/src/plugins/platforms/minimalegl/qminimaleglscreen.cpp b/src/plugins/platforms/minimalegl/qminimaleglscreen.cpp index d3d091fab7..0175d2dbdd 100644 --- a/src/plugins/platforms/minimalegl/qminimaleglscreen.cpp +++ b/src/plugins/platforms/minimalegl/qminimaleglscreen.cpp @@ -41,7 +41,9 @@ #include "qminimaleglwindow.h" #include <QtEglSupport/private/qeglconvenience_p.h> -#include <QtEglSupport/private/qeglplatformcontext_p.h> +#ifndef QT_NO_OPENGL +# include <QtEglSupport/private/qeglplatformcontext_p.h> +#endif #ifdef Q_OPENKODE #include <KD/kd.h> @@ -52,6 +54,8 @@ QT_BEGIN_NAMESPACE // #define QEGL_EXTRA_DEBUG +#ifndef QT_NO_OPENGL + class QMinimalEglContext : public QEGLPlatformContext { public: @@ -68,6 +72,8 @@ public: } }; +#endif + QMinimalEglScreen::QMinimalEglScreen(EGLNativeDisplayType display) : m_depth(32) , m_format(QImage::Format_Invalid) @@ -161,9 +167,10 @@ void QMinimalEglScreen::createAndSetPlatformContext() } // qWarning("Created surface %dx%d\n", w, h); +#ifndef QT_NO_OPENGL QEGLPlatformContext *platformContext = new QMinimalEglContext(platformFormat, 0, m_dpy); m_platformContext = platformContext; - +#endif EGLint w,h; // screen size detection eglQuerySurface(m_dpy, m_surface, EGL_WIDTH, &w); eglQuerySurface(m_dpy, m_surface, EGL_HEIGHT, &h); @@ -191,6 +198,7 @@ QImage::Format QMinimalEglScreen::format() const createAndSetPlatformContext(); return m_format; } +#ifndef QT_NO_OPENGL QPlatformOpenGLContext *QMinimalEglScreen::platformContext() const { if (!m_platformContext) { @@ -199,5 +207,5 @@ QPlatformOpenGLContext *QMinimalEglScreen::platformContext() const } return m_platformContext; } - +#endif QT_END_NAMESPACE diff --git a/src/plugins/platforms/minimalegl/qminimaleglscreen.h b/src/plugins/platforms/minimalegl/qminimaleglscreen.h index ba605835a8..24098b8127 100644 --- a/src/plugins/platforms/minimalegl/qminimaleglscreen.h +++ b/src/plugins/platforms/minimalegl/qminimaleglscreen.h @@ -59,9 +59,9 @@ public: QRect geometry() const Q_DECL_OVERRIDE; int depth() const Q_DECL_OVERRIDE; QImage::Format format() const Q_DECL_OVERRIDE; - +#ifndef QT_NO_OPENGL QPlatformOpenGLContext *platformContext() const; - +#endif EGLSurface surface() const { return m_surface; } private: diff --git a/src/plugins/platforms/mirclient/mirclient.pro b/src/plugins/platforms/mirclient/mirclient.pro index 0ba63601a9..d2da7e6ca0 100644 --- a/src/plugins/platforms/mirclient/mirclient.pro +++ b/src/plugins/platforms/mirclient/mirclient.pro @@ -5,6 +5,9 @@ QT += \ theme_support-private eventdispatcher_support-private \ fontdatabase_support-private egl_support-private +qtHaveModule(linuxaccessibility_support-private): \ + QT += linuxaccessibility_support-private + DEFINES += MESA_EGL_NO_X11_HEADERS # CONFIG += c++11 # only enables C++0x QMAKE_CXXFLAGS += -fvisibility=hidden -fvisibility-inlines-hidden -std=c++11 -Werror -Wall @@ -13,9 +16,12 @@ QMAKE_LFLAGS += -std=c++11 -Wl,-no-undefined QMAKE_USE_PRIVATE += mirclient SOURCES = \ + qmirclientappstatecontroller.cpp \ qmirclientbackingstore.cpp \ qmirclientclipboard.cpp \ qmirclientcursor.cpp \ + qmirclientdebugextension.cpp \ + qmirclientdesktopwindow.cpp \ qmirclientglcontext.cpp \ qmirclientinput.cpp \ qmirclientintegration.cpp \ @@ -23,13 +29,17 @@ SOURCES = \ qmirclientplatformservices.cpp \ qmirclientplugin.cpp \ qmirclientscreen.cpp \ + qmirclientscreenobserver.cpp \ qmirclienttheme.cpp \ qmirclientwindow.cpp HEADERS = \ + qmirclientappstatecontroller.h \ qmirclientbackingstore.h \ qmirclientclipboard.h \ qmirclientcursor.h \ + qmirclientdebugextension.h \ + qmirclientdesktopwindow.h \ qmirclientglcontext.h \ qmirclientinput.h \ qmirclientintegration.h \ @@ -39,9 +49,17 @@ HEADERS = \ qmirclientplatformservices.h \ qmirclientplugin.h \ qmirclientscreen.h \ + qmirclientscreenobserver.h \ qmirclienttheme.h \ qmirclientwindow.h +# libxkbcommon +!qtConfig(xkbcommon-system) { + include(../../../3rdparty/xkbcommon.pri) +} else { + QMAKE_USE += xkbcommon +} + PLUGIN_TYPE = platforms PLUGIN_CLASS_NAME = MirServerIntegrationPlugin !equals(TARGET, $$QT_DEFAULT_QPA_PLUGIN): PLUGIN_EXTENDS = - diff --git a/src/plugins/platforms/mirclient/qmirclientappstatecontroller.cpp b/src/plugins/platforms/mirclient/qmirclientappstatecontroller.cpp new file mode 100644 index 0000000000..69fc9b7aa7 --- /dev/null +++ b/src/plugins/platforms/mirclient/qmirclientappstatecontroller.cpp @@ -0,0 +1,102 @@ +/**************************************************************************** +** +** Copyright (C) 2016 Canonical, Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include "qmirclientappstatecontroller.h" + +#include <qpa/qwindowsysteminterface.h> + +/* + * QMirClientAppStateController - updates Qt's QApplication::applicationState property. + * + * Tries to avoid active-inactive-active invocations using a timer. The rapid state + * change can confuse some applications. + */ + +QMirClientAppStateController::QMirClientAppStateController() + : m_suspended(false) + , m_lastActive(true) +{ + m_inactiveTimer.setSingleShot(true); + m_inactiveTimer.setInterval(10); + QObject::connect(&m_inactiveTimer, &QTimer::timeout, []() + { + QWindowSystemInterface::handleApplicationStateChanged(Qt::ApplicationInactive); + }); +} + +void QMirClientAppStateController::setSuspended() +{ + m_inactiveTimer.stop(); + if (!m_suspended) { + m_suspended = true; + + QWindowSystemInterface::handleApplicationStateChanged(Qt::ApplicationSuspended); + } +} + +void QMirClientAppStateController::setResumed() +{ + m_inactiveTimer.stop(); + if (m_suspended) { + m_suspended = false; + + if (m_lastActive) { + QWindowSystemInterface::handleApplicationStateChanged(Qt::ApplicationActive); + } else { + QWindowSystemInterface::handleApplicationStateChanged(Qt::ApplicationInactive); + } + } +} + +void QMirClientAppStateController::setWindowFocused(bool focused) +{ + if (m_suspended) { + return; + } + + if (focused) { + m_inactiveTimer.stop(); + QWindowSystemInterface::handleApplicationStateChanged(Qt::ApplicationActive); + } else { + m_inactiveTimer.start(); + } + + m_lastActive = focused; +} diff --git a/src/plugins/platforms/mirclient/qmirclientappstatecontroller.h b/src/plugins/platforms/mirclient/qmirclientappstatecontroller.h new file mode 100644 index 0000000000..b3aa0022d9 --- /dev/null +++ b/src/plugins/platforms/mirclient/qmirclientappstatecontroller.h @@ -0,0 +1,62 @@ +/**************************************************************************** +** +** Copyright (C) 2016 Canonical, Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#ifndef QMIRCLIENTAPPSTATECONTROLLER_H +#define QMIRCLIENTAPPSTATECONTROLLER_H + +#include <QTimer> + +class QMirClientAppStateController +{ +public: + QMirClientAppStateController(); + + void setSuspended(); + void setResumed(); + + void setWindowFocused(bool focused); + +private: + bool m_suspended; + bool m_lastActive; + QTimer m_inactiveTimer; +}; + +#endif // QMIRCLIENTAPPSTATECONTROLLER_H diff --git a/src/plugins/platforms/mirclient/qmirclientbackingstore.cpp b/src/plugins/platforms/mirclient/qmirclientbackingstore.cpp index a4bb8864ab..51363619d9 100644 --- a/src/plugins/platforms/mirclient/qmirclientbackingstore.cpp +++ b/src/plugins/platforms/mirclient/qmirclientbackingstore.cpp @@ -61,6 +61,7 @@ QMirClientBackingStore::QMirClientBackingStore(QWindow* window) QMirClientBackingStore::~QMirClientBackingStore() { + mContext->makeCurrent(window()); // needed as QOpenGLTexture destructor assumes current context } void QMirClientBackingStore::flush(QWindow* window, const QRegion& region, const QPoint& offset) @@ -76,7 +77,6 @@ void QMirClientBackingStore::flush(QWindow* window, const QRegion& region, const mBlitter->create(); mBlitter->bind(); - mBlitter->setRedBlueSwizzle(true); mBlitter->blit(mTexture->textureId(), QMatrix4x4(), QOpenGLTextureBlitter::OriginTopLeft); mBlitter->release(); @@ -137,7 +137,9 @@ void QMirClientBackingStore::beginPaint(const QRegion& region) void QMirClientBackingStore::resize(const QSize& size, const QRegion& /*staticContents*/) { - mImage = QImage(size, QImage::Format_RGB32); + mImage = QImage(size, QImage::Format_RGBA8888); + + mContext->makeCurrent(window()); if (mTexture->isCreated()) mTexture->destroy(); @@ -147,3 +149,9 @@ QPaintDevice* QMirClientBackingStore::paintDevice() { return &mImage; } + +QImage QMirClientBackingStore::toImage() const +{ + // used by QPlatformBackingStore::composeAndFlush + return mImage; +} diff --git a/src/plugins/platforms/mirclient/qmirclientbackingstore.h b/src/plugins/platforms/mirclient/qmirclientbackingstore.h index 0c75e182ff..7644c77df2 100644 --- a/src/plugins/platforms/mirclient/qmirclientbackingstore.h +++ b/src/plugins/platforms/mirclient/qmirclientbackingstore.h @@ -58,6 +58,7 @@ public: void flush(QWindow* window, const QRegion& region, const QPoint& offset) override; void resize(const QSize& size, const QRegion& staticContents) override; QPaintDevice* paintDevice() override; + QImage toImage() const override; protected: void updateTexture(); diff --git a/src/plugins/platforms/mirclient/qmirclientclipboard.cpp b/src/plugins/platforms/mirclient/qmirclientclipboard.cpp index 4dff339f21..b9fc9b3b42 100644 --- a/src/plugins/platforms/mirclient/qmirclientclipboard.cpp +++ b/src/plugins/platforms/mirclient/qmirclientclipboard.cpp @@ -39,41 +39,36 @@ #include "qmirclientclipboard.h" +#include "qmirclientlogging.h" +#include "qmirclientwindow.h" +#include <QDBusPendingCallWatcher> +#include <QGuiApplication> +#include <QSignalBlocker> #include <QtCore/QMimeData> #include <QtCore/QStringList> -#include <QDBusInterface> -#include <QDBusPendingCallWatcher> -#include <QDBusPendingReply> - -// FIXME(loicm) The clipboard data format is not defined by Ubuntu Platform API -// which makes it impossible to have non-Qt applications communicate with Qt -// applications through the clipboard API. The solution would be to have -// Ubuntu Platform define the data format or propose an API that supports -// embedding different mime types in the clipboard. -// Data format: -// number of mime types (sizeof(int)) -// data layout ((4 * sizeof(int)) * number of mime types) -// mime type string offset (sizeof(int)) -// mime type string size (sizeof(int)) -// data offset (sizeof(int)) -// data size (sizeof(int)) -// data (n bytes) +// content-hub +#include <com/ubuntu/content/hub.h> -namespace { - -const int maxFormatsCount = 16; -const int maxBufferSize = 4 * 1024 * 1024; // 4 Mb - -} +// get this cumbersome nested namespace out of the way +using namespace com::ubuntu::content; QMirClientClipboard::QMirClientClipboard() : mMimeData(new QMimeData) - , mIsOutdated(true) - , mUpdatesDisabled(false) - , mDBusSetupDone(false) + , mContentHub(Hub::Client::instance()) { + connect(mContentHub, &Hub::pasteboardChanged, this, [this]() { + if (mClipboardState == QMirClientClipboard::SyncedClipboard) { + mClipboardState = QMirClientClipboard::OutdatedClipboard; + emitChanged(QClipboard::Clipboard); + } + }); + + connect(qGuiApp, &QGuiApplication::applicationStateChanged, + this, &QMirClientClipboard::onApplicationStateChanged); + + requestMimeData(); } QMirClientClipboard::~QMirClientClipboard() @@ -81,236 +76,106 @@ QMirClientClipboard::~QMirClientClipboard() delete mMimeData; } -void QMirClientClipboard::requestDBusClipboardContents() +QMimeData* QMirClientClipboard::mimeData(QClipboard::Mode mode) { - if (!mDBusSetupDone) { - setupDBus(); - } - - if (!mPendingGetContentsCall.isNull()) - return; + if (mode != QClipboard::Clipboard) + return nullptr; - QDBusPendingCall pendingCall = mDBusClipboard->asyncCall(QStringLiteral("GetContents")); + // Blocks dataChanged() signal from being emitted. Makes no sense to emit it from + // inside the data getter. + const QSignalBlocker blocker(this); - mPendingGetContentsCall = new QDBusPendingCallWatcher(pendingCall, this); + if (mClipboardState == OutdatedClipboard) { + updateMimeData(); + } else if (mClipboardState == SyncingClipboard) { + mPasteReply->waitForFinished(); + } - QObject::connect(mPendingGetContentsCall.data(), &QDBusPendingCallWatcher::finished, - this, &QMirClientClipboard::onDBusClipboardGetContentsFinished); + return mMimeData; } -void QMirClientClipboard::onDBusClipboardGetContentsFinished(QDBusPendingCallWatcher* call) +void QMirClientClipboard::setMimeData(QMimeData* mimeData, QClipboard::Mode mode) { - Q_ASSERT(call == mPendingGetContentsCall.data()); + QWindow *focusWindow = QGuiApplication::focusWindow(); + if (focusWindow && mode == QClipboard::Clipboard && mimeData != nullptr) { + QString surfaceId = static_cast<QMirClientWindow*>(focusWindow->handle())->persistentSurfaceId(); - QDBusPendingReply<QByteArray> reply = *call; - if (Q_UNLIKELY(reply.isError())) { - qCritical("QMirClientClipboard - Failed to get system clipboard contents via D-Bus. %s, %s", - qPrintable(reply.error().name()), qPrintable(reply.error().message())); - // TODO: Might try again later a number of times... - } else { - QByteArray serializedMimeData = reply.argumentAt<0>(); - updateMimeData(serializedMimeData); - } - call->deleteLater(); -} + QDBusPendingCall reply = mContentHub->createPaste(surfaceId, *mimeData); -void QMirClientClipboard::onDBusClipboardSetContentsFinished(QDBusPendingCallWatcher *call) -{ - QDBusPendingReply<void> reply = *call; - if (Q_UNLIKELY(reply.isError())) { - qCritical("QMirClientClipboard - Failed to set the system clipboard contents via D-Bus. %s, %s", - qPrintable(reply.error().name()), qPrintable(reply.error().message())); - // TODO: Might try again later a number of times... - } - call->deleteLater(); -} - -void QMirClientClipboard::updateMimeData(const QByteArray &serializedMimeData) -{ - if (mUpdatesDisabled) - return; + // Don't care whether it succeeded + QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(reply, this); + connect(watcher, &QDBusPendingCallWatcher::finished, + watcher, &QObject::deleteLater); - QMimeData *newMimeData = deserializeMimeData(serializedMimeData); - if (newMimeData) { - delete mMimeData; - mMimeData = newMimeData; - mIsOutdated = false; + mMimeData = mimeData; + mClipboardState = SyncedClipboard; emitChanged(QClipboard::Clipboard); - } else { - qWarning("QMirClientClipboard - Got invalid serialized mime data. Ignoring it."); } } -void QMirClientClipboard::setupDBus() -{ - QDBusConnection dbusConnection = QDBusConnection::sessionBus(); - - bool ok = dbusConnection.connect( - QStringLiteral("com.canonical.QtMir"), - QStringLiteral("/com/canonical/QtMir/Clipboard"), - QStringLiteral("com.canonical.QtMir.Clipboard"), - QStringLiteral("ContentsChanged"), - this, SLOT(updateMimeData(QByteArray))); - if (Q_UNLIKELY(!ok)) - qCritical("QMirClientClipboard - Failed to connect to ContentsChanged signal form the D-Bus system clipboard."); - - mDBusClipboard = new QDBusInterface(QStringLiteral("com.canonical.QtMir"), - QStringLiteral("/com/canonical/QtMir/Clipboard"), - QStringLiteral("com.canonical.QtMir.Clipboard"), - dbusConnection); - - mDBusSetupDone = true; -} - -QByteArray QMirClientClipboard::serializeMimeData(QMimeData *mimeData) const +bool QMirClientClipboard::supportsMode(QClipboard::Mode mode) const { - Q_ASSERT(mimeData != nullptr); - - const QStringList formats = mimeData->formats(); - const int formatCount = qMin(formats.size(), maxFormatsCount); - const int headerSize = sizeof(int) + (formatCount * 4 * sizeof(int)); - int bufferSize = headerSize; - - for (int i = 0; i < formatCount; i++) - bufferSize += formats[i].size() + mimeData->data(formats[i]).size(); - - QByteArray serializedMimeData; - if (bufferSize <= maxBufferSize) { - // Serialize data. - serializedMimeData.resize(bufferSize); - { - char *buffer = serializedMimeData.data(); - int* header = reinterpret_cast<int*>(serializedMimeData.data()); - int offset = headerSize; - header[0] = formatCount; - for (int i = 0; i < formatCount; i++) { - const QByteArray data = mimeData->data(formats[i]); - const int formatOffset = offset; - const int formatSize = formats[i].size(); - const int dataOffset = offset + formatSize; - const int dataSize = data.size(); - memcpy(&buffer[formatOffset], formats[i].toLatin1().data(), formatSize); - memcpy(&buffer[dataOffset], data.data(), dataSize); - header[i*4+1] = formatOffset; - header[i*4+2] = formatSize; - header[i*4+3] = dataOffset; - header[i*4+4] = dataSize; - offset += formatSize + dataSize; - } - } - } else { - qWarning("QMirClientClipboard: Not sending contents (%d bytes) to the global clipboard as it's" - " bigger than the maximum allowed size of %d bytes", bufferSize, maxBufferSize); - } - - return serializedMimeData; + return mode == QClipboard::Clipboard; } -QMimeData *QMirClientClipboard::deserializeMimeData(const QByteArray &serializedMimeData) const +bool QMirClientClipboard::ownsMode(QClipboard::Mode mode) const { - if (static_cast<std::size_t>(serializedMimeData.size()) < sizeof(int)) { - // Data is invalid - return nullptr; - } - - QMimeData *mimeData = new QMimeData; - - const char* const buffer = serializedMimeData.constData(); - const int* const header = reinterpret_cast<const int*>(serializedMimeData.constData()); - - const int count = qMin(header[0], maxFormatsCount); - - for (int i = 0; i < count; i++) { - const int formatOffset = header[i*4+1]; - const int formatSize = header[i*4+2]; - const int dataOffset = header[i*4+3]; - const int dataSize = header[i*4+4]; - - if (formatOffset + formatSize <= serializedMimeData.size() - && dataOffset + dataSize <= serializedMimeData.size()) { - - QString mimeType = QString::fromLatin1(&buffer[formatOffset], formatSize); - QByteArray mimeDataBytes(&buffer[dataOffset], dataSize); - - mimeData->setData(mimeType, mimeDataBytes); - } - } - - return mimeData; + Q_UNUSED(mode); + return false; } -QMimeData* QMirClientClipboard::mimeData(QClipboard::Mode mode) +void QMirClientClipboard::onApplicationStateChanged(Qt::ApplicationState state) { - if (mode != QClipboard::Clipboard) - return nullptr; - - if (mIsOutdated && mPendingGetContentsCall.isNull()) { - requestDBusClipboardContents(); + if (state == Qt::ApplicationActive) { + // Only focused or active applications might be allowed to paste, so we probably + // missed changes in the clipboard while we were hidden, inactive or, more importantly, + // suspended. + requestMimeData(); } - - // Return whatever we have at the moment instead of blocking until we have something. - // - // This might be called during app startup just for the sake of checking if some - // "Paste" UI control should be enabled or not. - // We will emit QClipboard::changed() once we finally have something. - return mMimeData; } -void QMirClientClipboard::setMimeData(QMimeData* mimeData, QClipboard::Mode mode) +void QMirClientClipboard::updateMimeData() { - if (mode != QClipboard::Clipboard) + if (qGuiApp->applicationState() != Qt::ApplicationActive) { + // Don't even bother asking as content-hub would probably ignore our request (and should). return; - - if (!mPendingGetContentsCall.isNull()) { - // Ignore whatever comes from the system clipboard as we are going to change it anyway - QObject::disconnect(mPendingGetContentsCall.data(), 0, this, 0); - mUpdatesDisabled = true; - mPendingGetContentsCall->waitForFinished(); - mUpdatesDisabled = false; - delete mPendingGetContentsCall.data(); } - if (mimeData != nullptr) { - QByteArray serializedMimeData = serializeMimeData(mimeData); - if (!serializedMimeData.isEmpty()) { - setDBusClipboardContents(serializedMimeData); - } + delete mMimeData; - mMimeData = mimeData; + QWindow *focusWindow = QGuiApplication::focusWindow(); + if (focusWindow) { + QString surfaceId = static_cast<QMirClientWindow*>(focusWindow->handle())->persistentSurfaceId(); + mMimeData = mContentHub->latestPaste(surfaceId); + mClipboardState = SyncedClipboard; emitChanged(QClipboard::Clipboard); } } -bool QMirClientClipboard::supportsMode(QClipboard::Mode mode) const -{ - return mode == QClipboard::Clipboard; -} - -bool QMirClientClipboard::ownsMode(QClipboard::Mode mode) const +void QMirClientClipboard::requestMimeData() { - Q_UNUSED(mode); - return false; -} - -void QMirClientClipboard::setDBusClipboardContents(const QByteArray &clipboardContents) -{ - if (!mDBusSetupDone) { - setupDBus(); + if (qGuiApp->applicationState() != Qt::ApplicationActive) { + // Don't even bother asking as content-hub would probably ignore our request (and should). + return; } - if (!mPendingSetContentsCall.isNull()) { - // Ignore any previous set call as we are going to overwrite it anyway - QObject::disconnect(mPendingSetContentsCall.data(), 0, this, 0); - mUpdatesDisabled = true; - mPendingSetContentsCall->waitForFinished(); - mUpdatesDisabled = false; - delete mPendingSetContentsCall.data(); + QWindow *focusWindow = QGuiApplication::focusWindow(); + if (!focusWindow) { + return; } - QDBusPendingCall pendingCall = mDBusClipboard->asyncCall(QStringLiteral("SetContents"), clipboardContents); - - mPendingSetContentsCall = new QDBusPendingCallWatcher(pendingCall, this); + QString surfaceId = static_cast<QMirClientWindow*>(focusWindow->handle())->persistentSurfaceId(); + QDBusPendingCall reply = mContentHub->requestLatestPaste(surfaceId); + mClipboardState = SyncingClipboard; - QObject::connect(mPendingSetContentsCall.data(), &QDBusPendingCallWatcher::finished, - this, &QMirClientClipboard::onDBusClipboardSetContentsFinished); + mPasteReply = new QDBusPendingCallWatcher(reply, this); + connect(mPasteReply, &QDBusPendingCallWatcher::finished, + this, [this]() { + delete mMimeData; + mMimeData = mContentHub->paste(*mPasteReply); + mClipboardState = SyncedClipboard; + mPasteReply->deleteLater(); + mPasteReply = nullptr; + emitChanged(QClipboard::Clipboard); + }); } diff --git a/src/plugins/platforms/mirclient/qmirclientclipboard.h b/src/plugins/platforms/mirclient/qmirclientclipboard.h index 1394498320..09e9bcdf38 100644 --- a/src/plugins/platforms/mirclient/qmirclientclipboard.h +++ b/src/plugins/platforms/mirclient/qmirclientclipboard.h @@ -45,7 +45,15 @@ #include <QMimeData> #include <QPointer> -class QDBusInterface; + +namespace com { + namespace ubuntu { + namespace content { + class Hub; + } + } +} + class QDBusPendingCallWatcher; class QMirClientClipboard : public QObject, public QPlatformClipboard @@ -61,31 +69,24 @@ public: bool supportsMode(QClipboard::Mode mode) const override; bool ownsMode(QClipboard::Mode mode) const override; - void requestDBusClipboardContents(); - private Q_SLOTS: - void onDBusClipboardGetContentsFinished(QDBusPendingCallWatcher*); - void onDBusClipboardSetContentsFinished(QDBusPendingCallWatcher*); - void updateMimeData(const QByteArray &serializedMimeData); + void onApplicationStateChanged(Qt::ApplicationState state); private: - void setupDBus(); - - QByteArray serializeMimeData(QMimeData *mimeData) const; - QMimeData *deserializeMimeData(const QByteArray &serializedMimeData) const; - - void setDBusClipboardContents(const QByteArray &clipboardContents); + void updateMimeData(); + void requestMimeData(); QMimeData *mMimeData; - bool mIsOutdated; - QPointer<QDBusInterface> mDBusClipboard; + enum { + OutdatedClipboard, // Our mimeData is outdated, need to fetch latest from ContentHub + SyncingClipboard, // Our mimeData is outdated and we are waiting for ContentHub to reply with the latest paste + SyncedClipboard // Our mimeData is in sync with what ContentHub has + } mClipboardState{OutdatedClipboard}; - QPointer<QDBusPendingCallWatcher> mPendingGetContentsCall; - QPointer<QDBusPendingCallWatcher> mPendingSetContentsCall; + com::ubuntu::content::Hub *mContentHub; - bool mUpdatesDisabled; - bool mDBusSetupDone; + QDBusPendingCallWatcher *mPasteReply{nullptr}; }; #endif // QMIRCLIENTCLIPBOARD_H diff --git a/src/plugins/platforms/mirclient/qmirclientcursor.cpp b/src/plugins/platforms/mirclient/qmirclientcursor.cpp index a0da3fdd77..812cde95c6 100644 --- a/src/plugins/platforms/mirclient/qmirclientcursor.cpp +++ b/src/plugins/platforms/mirclient/qmirclientcursor.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2015 Canonical, Ltd. +** Copyright (C) 2015-2016 Canonical, Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the plugins of the Qt Toolkit. @@ -45,35 +45,41 @@ #include <mir_toolkit/mir_client_library.h> +Q_LOGGING_CATEGORY(mirclientCursor, "qt.qpa.mirclient.cursor", QtWarningMsg) + QMirClientCursor::QMirClientCursor(MirConnection *connection) : mConnection(connection) { - mShapeToCursorName[Qt::ArrowCursor] = "left_ptr"; + /* + * TODO: Add the missing cursors to Mir (LP: #1388987) + * Those are the ones without a mir_ prefix, which are X11 cursors + * and won't be understood by any shell other than Unity8. + */ + mShapeToCursorName[Qt::ArrowCursor] = mir_arrow_cursor_name; mShapeToCursorName[Qt::UpArrowCursor] = "up_arrow"; - mShapeToCursorName[Qt::CrossCursor] = "cross"; - mShapeToCursorName[Qt::WaitCursor] = "watch"; - mShapeToCursorName[Qt::IBeamCursor] = "xterm"; - mShapeToCursorName[Qt::SizeVerCursor] = "size_ver"; - mShapeToCursorName[Qt::SizeHorCursor] = "size_hor"; - mShapeToCursorName[Qt::SizeBDiagCursor] = "size_bdiag"; - mShapeToCursorName[Qt::SizeFDiagCursor] = "size_fdiag"; - mShapeToCursorName[Qt::SizeAllCursor] = "size_all"; - mShapeToCursorName[Qt::BlankCursor] = "blank"; - mShapeToCursorName[Qt::SplitVCursor] = "split_v"; - mShapeToCursorName[Qt::SplitHCursor] = "split_h"; - mShapeToCursorName[Qt::PointingHandCursor] = "hand"; + mShapeToCursorName[Qt::CrossCursor] = mir_crosshair_cursor_name; + mShapeToCursorName[Qt::WaitCursor] = mir_busy_cursor_name; + mShapeToCursorName[Qt::IBeamCursor] = mir_caret_cursor_name; + mShapeToCursorName[Qt::SizeVerCursor] = mir_vertical_resize_cursor_name; + mShapeToCursorName[Qt::SizeHorCursor] = mir_horizontal_resize_cursor_name; + mShapeToCursorName[Qt::SizeBDiagCursor] = mir_diagonal_resize_bottom_to_top_cursor_name; + mShapeToCursorName[Qt::SizeFDiagCursor] = mir_diagonal_resize_top_to_bottom_cursor_name; + mShapeToCursorName[Qt::SizeAllCursor] = mir_omnidirectional_resize_cursor_name; + mShapeToCursorName[Qt::BlankCursor] = mir_disabled_cursor_name; + mShapeToCursorName[Qt::SplitVCursor] = mir_vsplit_resize_cursor_name; + mShapeToCursorName[Qt::SplitHCursor] = mir_hsplit_resize_cursor_name; + mShapeToCursorName[Qt::PointingHandCursor] = mir_pointing_hand_cursor_name; mShapeToCursorName[Qt::ForbiddenCursor] = "forbidden"; mShapeToCursorName[Qt::WhatsThisCursor] = "whats_this"; mShapeToCursorName[Qt::BusyCursor] = "left_ptr_watch"; - mShapeToCursorName[Qt::OpenHandCursor] = "openhand"; - mShapeToCursorName[Qt::ClosedHandCursor] = "closedhand"; + mShapeToCursorName[Qt::OpenHandCursor] = mir_open_hand_cursor_name; + mShapeToCursorName[Qt::ClosedHandCursor] = mir_closed_hand_cursor_name; mShapeToCursorName[Qt::DragCopyCursor] = "dnd-copy"; mShapeToCursorName[Qt::DragMoveCursor] = "dnd-move"; mShapeToCursorName[Qt::DragLinkCursor] = "dnd-link"; } namespace { -#if !defined(QT_NO_DEBUG) const char *qtCursorShapeToStr(Qt::CursorShape shape) { switch (shape) { @@ -127,7 +133,6 @@ const char *qtCursorShapeToStr(Qt::CursorShape shape) return "???"; } } -#endif // !defined(QT_NO_DEBUG) } // anonymous namespace void QMirClientCursor::changeCursor(QCursor *windowCursor, QWindow *window) @@ -144,7 +149,7 @@ void QMirClientCursor::changeCursor(QCursor *windowCursor, QWindow *window) if (windowCursor) { - DLOG("[ubuntumirclient QPA] changeCursor shape=%s, window=%p\n", qtCursorShapeToStr(windowCursor->shape()), window); + qCDebug(mirclientCursor, "changeCursor shape=%s, window=%p", qtCursorShapeToStr(windowCursor->shape()), window); if (!windowCursor->pixmap().isNull()) { configureMirCursorWithPixmapQCursor(surface, *windowCursor); } else if (windowCursor->shape() == Qt::BitmapCursor) { diff --git a/src/plugins/platforms/mirclient/qmirclientcursor.h b/src/plugins/platforms/mirclient/qmirclientcursor.h index 4ecc3d97ee..c5de23b272 100644 --- a/src/plugins/platforms/mirclient/qmirclientcursor.h +++ b/src/plugins/platforms/mirclient/qmirclientcursor.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2015 Canonical, Ltd. +** Copyright (C) 2015-2016 Canonical, Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the plugins of the Qt Toolkit. diff --git a/src/plugins/platforms/mirclient/qmirclientdebugextension.cpp b/src/plugins/platforms/mirclient/qmirclientdebugextension.cpp new file mode 100644 index 0000000000..9aa934083d --- /dev/null +++ b/src/plugins/platforms/mirclient/qmirclientdebugextension.cpp @@ -0,0 +1,79 @@ +/**************************************************************************** +** +** Copyright (C) 2016 Canonical, Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include "qmirclientdebugextension.h" + +#include "qmirclientlogging.h" + +// mir client debug +#include <mir_toolkit/debug/surface.h> + +Q_LOGGING_CATEGORY(mirclientDebug, "qt.qpa.mirclient.debug") + +QMirClientDebugExtension::QMirClientDebugExtension() + : m_mirclientDebug(QStringLiteral("mirclient-debug-extension"), 1) + , m_mapper(nullptr) +{ + qCDebug(mirclientDebug) << "NOTICE: Loading mirclient-debug-extension"; + m_mapper = (MapperPrototype) m_mirclientDebug.resolve("mir_debug_surface_coords_to_screen"); + + if (!m_mirclientDebug.isLoaded()) { + qCWarning(mirclientDebug) << "ERROR: mirclient-debug-extension failed to load:" + << m_mirclientDebug.errorString(); + } else if (!m_mapper) { + qCWarning(mirclientDebug) << "ERROR: unable to find required symbols in mirclient-debug-extension:" + << m_mirclientDebug.errorString(); + } +} + +QPoint QMirClientDebugExtension::mapSurfacePointToScreen(MirSurface *surface, const QPoint &point) +{ + if (!m_mapper) { + return point; + } + + QPoint mappedPoint; + bool status = m_mapper(surface, point.x(), point.y(), &mappedPoint.rx(), &mappedPoint.ry()); + if (status) { + return mappedPoint; + } else { + return point; + } +} diff --git a/src/plugins/platforms/mirclient/qmirclientdebugextension.h b/src/plugins/platforms/mirclient/qmirclientdebugextension.h new file mode 100644 index 0000000000..0596561d77 --- /dev/null +++ b/src/plugins/platforms/mirclient/qmirclientdebugextension.h @@ -0,0 +1,63 @@ +/**************************************************************************** +** +** Copyright (C) 2016 Canonical, Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#ifndef QMIRCLIENTDEBUGEXTENSION_H +#define QMIRCLIENTDEBUGEXTENSION_H + +#include <QPoint> +#include <QLibrary> +struct MirSurface; + +typedef bool (*MapperPrototype)(MirSurface* surface, int x, int y, int* screenX, int* screenY); + + +class QMirClientDebugExtension +{ +public: + QMirClientDebugExtension(); + + QPoint mapSurfacePointToScreen(MirSurface *, const QPoint &point); + +private: + QLibrary m_mirclientDebug; + MapperPrototype m_mapper; +}; + +#endif // QMIRCLIENTDEBUGEXTENSION_H diff --git a/src/plugins/platforms/mirclient/qmirclientdesktopwindow.cpp b/src/plugins/platforms/mirclient/qmirclientdesktopwindow.cpp new file mode 100644 index 0000000000..123f805c25 --- /dev/null +++ b/src/plugins/platforms/mirclient/qmirclientdesktopwindow.cpp @@ -0,0 +1,50 @@ +/**************************************************************************** +** +** Copyright (C) 2016 Canonical, Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include "qmirclientdesktopwindow.h" + +// local +#include "qmirclientlogging.h" + +QMirClientDesktopWindow::QMirClientDesktopWindow(QWindow *window) + : QPlatformWindow(window) +{ + qCDebug(mirclient, "QMirClientDesktopWindow(window=%p)", window); +} diff --git a/src/plugins/platforms/mirclient/qmirclientdesktopwindow.h b/src/plugins/platforms/mirclient/qmirclientdesktopwindow.h new file mode 100644 index 0000000000..3ba54db826 --- /dev/null +++ b/src/plugins/platforms/mirclient/qmirclientdesktopwindow.h @@ -0,0 +1,53 @@ +/**************************************************************************** +** +** Copyright (C) 2016 Canonical, Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#ifndef QMIRCLIENTDESKTOPWINDOW_H +#define QMIRCLIENTDESKTOPWINDOW_H + +#include <qpa/qplatformwindow.h> + +// TODO Implement it. For now it's just an empty, dummy class. +class QMirClientDesktopWindow : public QPlatformWindow +{ +public: + QMirClientDesktopWindow(QWindow*); +}; + +#endif // QMIRCLIENTDESKTOPWINDOW_H diff --git a/src/plugins/platforms/mirclient/qmirclientglcontext.cpp b/src/plugins/platforms/mirclient/qmirclientglcontext.cpp index 38eb0a4609..fc7d90d5ec 100644 --- a/src/plugins/platforms/mirclient/qmirclientglcontext.cpp +++ b/src/plugins/platforms/mirclient/qmirclientglcontext.cpp @@ -39,123 +39,94 @@ #include "qmirclientglcontext.h" -#include "qmirclientwindow.h" #include "qmirclientlogging.h" +#include "qmirclientwindow.h" + +#include <QOpenGLFramebufferObject> #include <QtEglSupport/private/qeglconvenience_p.h> +#include <QtEglSupport/private/qeglpbuffer_p.h> #include <QtGui/private/qopenglcontext_p.h> -#include <dlfcn.h> - -#if !defined(QT_NO_DEBUG) -static void printOpenGLESConfig() { - static bool once = true; - if (once) { - const char* string = (const char*) glGetString(GL_VENDOR); - LOG("OpenGL ES vendor: %s", string); - string = (const char*) glGetString(GL_RENDERER); - LOG("OpenGL ES renderer: %s", string); - string = (const char*) glGetString(GL_VERSION); - LOG("OpenGL ES version: %s", string); - string = (const char*) glGetString(GL_SHADING_LANGUAGE_VERSION); - LOG("OpenGL ES Shading Language version: %s", string); - string = (const char*) glGetString(GL_EXTENSIONS); - LOG("OpenGL ES extensions: %s", string); - once = false; - } -} -#endif -static EGLenum api_in_use() +Q_LOGGING_CATEGORY(mirclientGraphics, "qt.qpa.mirclient.graphics", QtWarningMsg) + +namespace { + +void printEglConfig(EGLDisplay display, EGLConfig config) { -#ifdef QTUBUNTU_USE_OPENGL - return EGL_OPENGL_API; -#else - return EGL_OPENGL_ES_API; -#endif + Q_ASSERT(display != EGL_NO_DISPLAY); + Q_ASSERT(config != nullptr); + + const char *string = eglQueryString(display, EGL_VENDOR); + qCDebug(mirclientGraphics, "EGL vendor: %s", string); + + string = eglQueryString(display, EGL_VERSION); + qCDebug(mirclientGraphics, "EGL version: %s", string); + + string = eglQueryString(display, EGL_EXTENSIONS); + qCDebug(mirclientGraphics, "EGL extensions: %s", string); + + qCDebug(mirclientGraphics, "EGL configuration attributes:"); + q_printEglConfig(display, config); } -QMirClientOpenGLContext::QMirClientOpenGLContext(QMirClientScreen* screen, QMirClientOpenGLContext* share) +} // anonymous namespace + +QMirClientOpenGLContext::QMirClientOpenGLContext(const QSurfaceFormat &format, QPlatformOpenGLContext *share, + EGLDisplay display) + : QEGLPlatformContext(format, share, display, 0) { - ASSERT(screen != NULL); - mEglDisplay = screen->eglDisplay(); - mScreen = screen; - - // Create an OpenGL ES 2 context. - QVector<EGLint> attribs; - attribs.append(EGL_CONTEXT_CLIENT_VERSION); - attribs.append(2); - attribs.append(EGL_NONE); - ASSERT(eglBindAPI(api_in_use()) == EGL_TRUE); - - mEglContext = eglCreateContext(mEglDisplay, screen->eglConfig(), share ? share->eglContext() : EGL_NO_CONTEXT, - attribs.constData()); - DASSERT(mEglContext != EGL_NO_CONTEXT); + if (mirclientGraphics().isDebugEnabled()) { + printEglConfig(display, eglConfig()); + } } -QMirClientOpenGLContext::~QMirClientOpenGLContext() +static bool needsFBOReadBackWorkaround() { - ASSERT(eglDestroyContext(mEglDisplay, mEglContext) == EGL_TRUE); + static bool set = false; + static bool needsWorkaround = false; + + if (Q_UNLIKELY(!set)) { + const char *rendererString = reinterpret_cast<const char *>(glGetString(GL_RENDERER)); + needsWorkaround = qstrncmp(rendererString, "Mali-400", 8) == 0 + || qstrncmp(rendererString, "Mali-T7", 7) == 0 + || qstrncmp(rendererString, "PowerVR Rogue G6200", 19) == 0; + set = true; + } + + return needsWorkaround; } bool QMirClientOpenGLContext::makeCurrent(QPlatformSurface* surface) { - DASSERT(surface->surface()->surfaceType() == QSurface::OpenGLSurface); - EGLSurface eglSurface = static_cast<QMirClientWindow*>(surface)->eglSurface(); -#if defined(QT_NO_DEBUG) - eglBindAPI(api_in_use()); - eglMakeCurrent(mEglDisplay, eglSurface, eglSurface, mEglContext); -#else - ASSERT(eglBindAPI(api_in_use()) == EGL_TRUE); - ASSERT(eglMakeCurrent(mEglDisplay, eglSurface, eglSurface, mEglContext) == EGL_TRUE); - printOpenGLESConfig(); -#endif - - // When running on the emulator, shaders will be compiled using a thin wrapper around the desktop drivers. - // These wrappers might not support the precision qualifiers, so set the workaround flag to true. - const char *rendererString = reinterpret_cast<const char *>(glGetString(GL_RENDERER)); - if (rendererString != 0 && qstrncmp(rendererString, "Android Emulator", 16) == 0) { + const bool ret = QEGLPlatformContext::makeCurrent(surface); + + if (Q_LIKELY(ret)) { QOpenGLContextPrivate *ctx_d = QOpenGLContextPrivate::get(context()); - ctx_d->workaround_missingPrecisionQualifiers = true; + if (!ctx_d->workaround_brokenFBOReadBack && needsFBOReadBackWorkaround()) { + ctx_d->workaround_brokenFBOReadBack = true; + } } - - return true; + return ret; } -void QMirClientOpenGLContext::doneCurrent() +// Following method used internally in the base class QEGLPlatformContext to access +// the egl surface of a QPlatformSurface/QMirClientWindow +EGLSurface QMirClientOpenGLContext::eglSurfaceForPlatformSurface(QPlatformSurface *surface) { -#if defined(QT_NO_DEBUG) - eglBindAPI(api_in_use()); - eglMakeCurrent(mEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); -#else - ASSERT(eglBindAPI(api_in_use()) == EGL_TRUE); - ASSERT(eglMakeCurrent(mEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT) == EGL_TRUE); -#endif + if (surface->surface()->surfaceClass() == QSurface::Window) { + return static_cast<QMirClientWindow *>(surface)->eglSurface(); + } else { + return static_cast<QEGLPbuffer *>(surface)->pbuffer(); + } } void QMirClientOpenGLContext::swapBuffers(QPlatformSurface* surface) { - QMirClientWindow *ubuntuWindow = static_cast<QMirClientWindow*>(surface); - - EGLSurface eglSurface = ubuntuWindow->eglSurface(); -#if defined(QT_NO_DEBUG) - eglBindAPI(api_in_use()); - eglSwapBuffers(mEglDisplay, eglSurface); -#else - ASSERT(eglBindAPI(api_in_use()) == EGL_TRUE); - ASSERT(eglSwapBuffers(mEglDisplay, eglSurface) == EGL_TRUE); -#endif - - ubuntuWindow->onSwapBuffersDone(); -} + QEGLPlatformContext::swapBuffers(surface); -QFunctionPointer QMirClientOpenGLContext::getProcAddress(const char *procName) -{ -#if defined(QT_NO_DEBUG) - eglBindAPI(api_in_use()); -#else - ASSERT(eglBindAPI(api_in_use()) == EGL_TRUE); -#endif - QFunctionPointer proc = (QFunctionPointer) eglGetProcAddress(procName); - if (!proc) - proc = (QFunctionPointer) dlsym(RTLD_DEFAULT, procName); - return proc; + if (surface->surface()->surfaceClass() == QSurface::Window) { + // notify window on swap completion + auto platformWindow = static_cast<QMirClientWindow *>(surface); + platformWindow->onSwapBuffersDone(); + } } diff --git a/src/plugins/platforms/mirclient/qmirclientglcontext.h b/src/plugins/platforms/mirclient/qmirclientglcontext.h index eac0b78c4e..92331a6fb1 100644 --- a/src/plugins/platforms/mirclient/qmirclientglcontext.h +++ b/src/plugins/platforms/mirclient/qmirclientglcontext.h @@ -42,28 +42,22 @@ #define QMIRCLIENTGLCONTEXT_H #include <qpa/qplatformopenglcontext.h> -#include "qmirclientscreen.h" +#include <QtEglSupport/private/qeglplatformcontext_p.h> -class QMirClientOpenGLContext : public QPlatformOpenGLContext +#include <EGL/egl.h> + +class QMirClientOpenGLContext : public QEGLPlatformContext { public: - QMirClientOpenGLContext(QMirClientScreen* screen, QMirClientOpenGLContext* share); - virtual ~QMirClientOpenGLContext(); - - // QPlatformOpenGLContext methods. - QSurfaceFormat format() const override { return mScreen->surfaceFormat(); } - void swapBuffers(QPlatformSurface* surface) override; - bool makeCurrent(QPlatformSurface* surface) override; - void doneCurrent() override; - bool isValid() const override { return mEglContext != EGL_NO_CONTEXT; } - QFunctionPointer getProcAddress(const char *procName) override; + QMirClientOpenGLContext(const QSurfaceFormat &format, QPlatformOpenGLContext *share, + EGLDisplay display); - EGLContext eglContext() const { return mEglContext; } + // QEGLPlatformContext methods. + void swapBuffers(QPlatformSurface *surface) final; + bool makeCurrent(QPlatformSurface *surface) final; -private: - QMirClientScreen* mScreen; - EGLContext mEglContext; - EGLDisplay mEglDisplay; +protected: + EGLSurface eglSurfaceForPlatformSurface(QPlatformSurface *surface) final; }; #endif // QMIRCLIENTGLCONTEXT_H diff --git a/src/plugins/platforms/mirclient/qmirclientinput.cpp b/src/plugins/platforms/mirclient/qmirclientinput.cpp index b3b21ae0e3..ea13f3cc17 100644 --- a/src/plugins/platforms/mirclient/qmirclientinput.cpp +++ b/src/plugins/platforms/mirclient/qmirclientinput.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2014-2015 Canonical, Ltd. +** Copyright (C) 2014-2016 Canonical, Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the plugins of the Qt Toolkit. @@ -48,21 +48,23 @@ #include "qmirclientorientationchangeevent_p.h" // Qt -#if !defined(QT_NO_DEBUG) #include <QtCore/QThread> -#endif #include <QtCore/qglobal.h> #include <QtCore/QCoreApplication> -#include <private/qguiapplication_p.h> +#include <QtGui/private/qguiapplication_p.h> #include <qpa/qplatforminputcontext.h> #include <qpa/qwindowsysteminterface.h> +#include <QTextCodec> #include <xkbcommon/xkbcommon.h> #include <xkbcommon/xkbcommon-keysyms.h> #include <mir_toolkit/mir_client_library.h> -#define LOG_EVENTS 0 +Q_LOGGING_CATEGORY(mirclientInput, "qt.qpa.mirclient.input", QtWarningMsg) + +namespace +{ // XKB Keysyms which do not map directly to Qt types (i.e. Unicode points) static const uint32_t KeyTable[] = { @@ -134,6 +136,27 @@ static const uint32_t KeyTable[] = { XKB_KEY_MultipleCandidate, Qt::Key_MultipleCandidate, XKB_KEY_PreviousCandidate, Qt::Key_PreviousCandidate, + // dead keys + XKB_KEY_dead_grave, Qt::Key_Dead_Grave, + XKB_KEY_dead_acute, Qt::Key_Dead_Acute, + XKB_KEY_dead_circumflex, Qt::Key_Dead_Circumflex, + XKB_KEY_dead_tilde, Qt::Key_Dead_Tilde, + XKB_KEY_dead_macron, Qt::Key_Dead_Macron, + XKB_KEY_dead_breve, Qt::Key_Dead_Breve, + XKB_KEY_dead_abovedot, Qt::Key_Dead_Abovedot, + XKB_KEY_dead_diaeresis, Qt::Key_Dead_Diaeresis, + XKB_KEY_dead_abovering, Qt::Key_Dead_Abovering, + XKB_KEY_dead_doubleacute, Qt::Key_Dead_Doubleacute, + XKB_KEY_dead_caron, Qt::Key_Dead_Caron, + XKB_KEY_dead_cedilla, Qt::Key_Dead_Cedilla, + XKB_KEY_dead_ogonek, Qt::Key_Dead_Ogonek, + XKB_KEY_dead_iota, Qt::Key_Dead_Iota, + XKB_KEY_dead_voiced_sound, Qt::Key_Dead_Voiced_Sound, + XKB_KEY_dead_semivoiced_sound, Qt::Key_Dead_Semivoiced_Sound, + XKB_KEY_dead_belowdot, Qt::Key_Dead_Belowdot, + XKB_KEY_dead_hook, Qt::Key_Dead_Hook, + XKB_KEY_dead_horn, Qt::Key_Dead_Horn, + XKB_KEY_Mode_switch, Qt::Key_Mode_switch, XKB_KEY_script_switch, Qt::Key_Mode_switch, XKB_KEY_XF86AudioRaiseVolume, Qt::Key_VolumeUp, @@ -144,14 +167,37 @@ static const uint32_t KeyTable[] = { 0, 0 }; -class QMirClientEvent : public QEvent +Qt::WindowState mirSurfaceStateToWindowState(MirSurfaceState state) +{ + switch (state) { + case mir_surface_state_fullscreen: + return Qt::WindowFullScreen; + case mir_surface_state_maximized: + case mir_surface_state_vertmaximized: + case mir_surface_state_horizmaximized: + return Qt::WindowMaximized; + case mir_surface_state_minimized: + return Qt::WindowMinimized; + case mir_surface_state_hidden: + // We should be handling this state separately. + Q_ASSERT(false); + case mir_surface_state_restored: + case mir_surface_state_unknown: + default: + return Qt::WindowNoState; + } +} + +} // namespace + +class UbuntuEvent : public QEvent { public: - QMirClientEvent(QMirClientWindow* window, const MirEvent *event, QEvent::Type type) + UbuntuEvent(QMirClientWindow* window, const MirEvent *event, QEvent::Type type) : QEvent(type), window(window) { nativeEvent = mir_event_ref(event); } - ~QMirClientEvent() + ~UbuntuEvent() { mir_event_unref(nativeEvent); } @@ -166,7 +212,7 @@ QMirClientInput::QMirClientInput(QMirClientClientIntegration* integration) , mEventFilterType(static_cast<QMirClientNativeInterface*>( integration->nativeInterface())->genericEventFilterType()) , mEventType(static_cast<QEvent::Type>(QEvent::registerEventType())) - , mLastFocusedWindow(nullptr) + , mLastInputWindow(nullptr) { // Initialize touch device. mTouchDevice = new QTouchDevice; @@ -182,42 +228,47 @@ QMirClientInput::~QMirClientInput() // Qt will take care of deleting mTouchDevice. } -#if (LOG_EVENTS != 0) static const char* nativeEventTypeToStr(MirEventType t) { switch (t) { case mir_event_type_key: - return "mir_event_type_key"; + return "key"; case mir_event_type_motion: - return "mir_event_type_motion"; + return "motion"; case mir_event_type_surface: - return "mir_event_type_surface"; + return "surface"; case mir_event_type_resize: - return "mir_event_type_resize"; + return "resize"; case mir_event_type_prompt_session_state_change: - return "mir_event_type_prompt_session_state_change"; + return "prompt_session_state_change"; case mir_event_type_orientation: - return "mir_event_type_orientation"; + return "orientation"; case mir_event_type_close_surface: - return "mir_event_type_close_surface"; + return "close_surface"; case mir_event_type_input: - return "mir_event_type_input"; + return "input"; + case mir_event_type_keymap: + return "keymap"; + case mir_event_type_input_configuration: + return "input_configuration"; + case mir_event_type_surface_output: + return "surface_output"; + case mir_event_type_input_device_state: + return "input_device_state"; default: - DLOG("Invalid event type %d", t); - return "invalid"; + return "unknown"; } } -#endif // LOG_EVENTS != 0 void QMirClientInput::customEvent(QEvent* event) { - DASSERT(QThread::currentThread() == thread()); - QMirClientEvent* ubuntuEvent = static_cast<QMirClientEvent*>(event); + Q_ASSERT(QThread::currentThread() == thread()); + UbuntuEvent* ubuntuEvent = static_cast<UbuntuEvent*>(event); const MirEvent *nativeEvent = ubuntuEvent->nativeEvent; if ((ubuntuEvent->window == nullptr) || (ubuntuEvent->window->window() == nullptr)) { - qWarning("Attempted to deliver an event to a non-existent window, ignoring."); + qCWarning(mirclient) << "Attempted to deliver an event to a non-existent window, ignoring."; return; } @@ -226,13 +277,11 @@ void QMirClientInput::customEvent(QEvent* event) if (QWindowSystemInterface::handleNativeEvent( ubuntuEvent->window->window(), mEventFilterType, const_cast<void *>(static_cast<const void *>(nativeEvent)), &result) == true) { - DLOG("event filtered out by native interface"); + qCDebug(mirclient, "event filtered out by native interface"); return; } - #if (LOG_EVENTS != 0) - LOG("QMirClientInput::customEvent(type=%s)", nativeEventTypeToStr(mir_event_get_type(nativeEvent))); - #endif + qCDebug(mirclientInput, "customEvent(type=%s)", nativeEventTypeToStr(mir_event_get_type(nativeEvent))); // Event dispatching. switch (mir_event_get_type(nativeEvent)) @@ -242,43 +291,30 @@ void QMirClientInput::customEvent(QEvent* event) break; case mir_event_type_resize: { - Q_ASSERT(ubuntuEvent->window->screen() == mIntegration->screen()); - auto resizeEvent = mir_event_get_resize_event(nativeEvent); - mIntegration->screen()->handleWindowSurfaceResize( - mir_resize_event_get_width(resizeEvent), - mir_resize_event_get_height(resizeEvent)); + // Enable workaround for Screen rotation + auto const targetWindow = ubuntuEvent->window; + if (targetWindow) { + auto const screen = static_cast<QMirClientScreen*>(targetWindow->screen()); + if (screen) { + screen->handleWindowSurfaceResize( + mir_resize_event_get_width(resizeEvent), + mir_resize_event_get_height(resizeEvent)); + } - ubuntuEvent->window->handleSurfaceResized(mir_resize_event_get_width(resizeEvent), - mir_resize_event_get_height(resizeEvent)); + targetWindow->handleSurfaceResized( + mir_resize_event_get_width(resizeEvent), + mir_resize_event_get_height(resizeEvent)); + } break; } case mir_event_type_surface: - { - auto surfaceEvent = mir_event_get_surface_event(nativeEvent); - if (mir_surface_event_get_attribute(surfaceEvent) == mir_surface_attrib_focus) { - const bool focused = mir_surface_event_get_attribute_value(surfaceEvent) == mir_surface_focused; - // Mir may have sent a pair of focus lost/gained events, so we need to "peek" into the queue - // so that we don't deactivate windows prematurely. - if (focused) { - mPendingFocusGainedEvents--; - ubuntuEvent->window->handleSurfaceFocused(); - QWindowSystemInterface::handleWindowActivated(ubuntuEvent->window->window(), Qt::ActiveWindowFocusReason); - - // NB: Since processing of system events is queued, never check qGuiApp->applicationState() - // as it might be outdated. Always call handleApplicationStateChanged() with the latest - // state regardless. - QWindowSystemInterface::handleApplicationStateChanged(Qt::ApplicationActive); - - } else if (!mPendingFocusGainedEvents) { - DLOG("[ubuntumirclient QPA] No windows have focus"); - QWindowSystemInterface::handleWindowActivated(nullptr, Qt::ActiveWindowFocusReason); - QWindowSystemInterface::handleApplicationStateChanged(Qt::ApplicationInactive); - } - } + handleSurfaceEvent(ubuntuEvent->window, mir_event_get_surface_event(nativeEvent)); + break; + case mir_event_type_surface_output: + handleSurfaceOutputEvent(ubuntuEvent->window, mir_event_get_surface_output_event(nativeEvent)); break; - } case mir_event_type_orientation: dispatchOrientationEvent(ubuntuEvent->window->window(), mir_event_get_orientation_event(nativeEvent)); break; @@ -286,7 +322,7 @@ void QMirClientInput::customEvent(QEvent* event) QWindowSystemInterface::handleCloseEvent(ubuntuEvent->window->window()); break; default: - DLOG("unhandled event type: %d", static_cast<int>(mir_event_get_type(nativeEvent))); + qCDebug(mirclient, "unhandled event type: %d", static_cast<int>(mir_event_get_type(nativeEvent))); } } @@ -294,22 +330,11 @@ void QMirClientInput::postEvent(QMirClientWindow *platformWindow, const MirEvent { QWindow *window = platformWindow->window(); - const auto eventType = mir_event_get_type(event); - if (mir_event_type_surface == eventType) { - auto surfaceEvent = mir_event_get_surface_event(event); - if (mir_surface_attrib_focus == mir_surface_event_get_attribute(surfaceEvent)) { - const bool focused = mir_surface_event_get_attribute_value(surfaceEvent) == mir_surface_focused; - if (focused) { - mPendingFocusGainedEvents++; - } - } - } - - QCoreApplication::postEvent(this, new QMirClientEvent( + QCoreApplication::postEvent(this, new UbuntuEvent( platformWindow, event, mEventType)); if ((window->flags().testFlag(Qt::WindowTransparentForInput)) && window->parent()) { - QCoreApplication::postEvent(this, new QMirClientEvent( + QCoreApplication::postEvent(this, new UbuntuEvent( static_cast<QMirClientWindow*>(platformWindow->QPlatformWindow::parent()), event, mEventType)); } @@ -365,15 +390,17 @@ void QMirClientInput::dispatchTouchEvent(QMirClientWindow *window, const MirInpu switch (touch_action) { case mir_touch_action_down: - mLastFocusedWindow = window; + mLastInputWindow = window; touchPoint.state = Qt::TouchPointPressed; break; case mir_touch_action_up: touchPoint.state = Qt::TouchPointReleased; break; case mir_touch_action_change: - default: touchPoint.state = Qt::TouchPointMoved; + break; + default: + Q_UNREACHABLE(); } touchPoints.append(touchPoint); @@ -384,22 +411,26 @@ void QMirClientInput::dispatchTouchEvent(QMirClientWindow *window, const MirInpu mTouchDevice, touchPoints); } -static uint32_t translateKeysym(uint32_t sym, char *string, size_t size) -{ - Q_UNUSED(size); - string[0] = '\0'; +static uint32_t translateKeysym(uint32_t sym, const QString &text) { + int code = 0; - if (sym >= XKB_KEY_F1 && sym <= XKB_KEY_F35) + QTextCodec *systemCodec = QTextCodec::codecForLocale(); + if (sym < 128 || (sym < 256 && systemCodec->mibEnum() == 4)) { + // upper-case key, if known + code = isprint((int)sym) ? toupper((int)sym) : 0; + } else if (sym >= XKB_KEY_F1 && sym <= XKB_KEY_F35) { return Qt::Key_F1 + (int(sym) - XKB_KEY_F1); - - for (int i = 0; KeyTable[i]; i += 2) { - if (sym == KeyTable[i]) - return KeyTable[i + 1]; + } else if (text.length() == 1 && text.unicode()->unicode() > 0x1f + && text.unicode()->unicode() != 0x7f + && !(sym >= XKB_KEY_dead_grave && sym <= XKB_KEY_dead_currency)) { + code = text.unicode()->toUpper().unicode(); + } else { + for (int i = 0; KeyTable[i]; i += 2) + if (sym == KeyTable[i]) + code = KeyTable[i + 1]; } - string[0] = sym; - string[1] = '\0'; - return toupper(sym); + return code; } namespace @@ -413,12 +444,15 @@ Qt::KeyboardModifiers qt_modifiers_from_mir(MirInputEventModifiers modifiers) if (modifiers & mir_input_event_modifier_ctrl) { q_modifiers |= Qt::ControlModifier; } - if (modifiers & mir_input_event_modifier_alt) { + if (modifiers & mir_input_event_modifier_alt_left) { q_modifiers |= Qt::AltModifier; } if (modifiers & mir_input_event_modifier_meta) { q_modifiers |= Qt::MetaModifier; } + if (modifiers & mir_input_event_modifier_alt_right) { + q_modifiers |= Qt::GroupSwitchModifier; + } return q_modifiers; } } @@ -429,34 +463,43 @@ void QMirClientInput::dispatchKeyEvent(QMirClientWindow *window, const MirInputE ulong timestamp = mir_input_event_get_event_time(event) / 1000000; xkb_keysym_t xk_sym = mir_keyboard_event_key_code(key_event); + quint32 scan_code = mir_keyboard_event_scan_code(key_event); + quint32 native_modifiers = mir_keyboard_event_modifiers(key_event); // Key modifier and unicode index mapping. - auto modifiers = qt_modifiers_from_mir(mir_keyboard_event_modifiers(key_event)); + auto modifiers = qt_modifiers_from_mir(native_modifiers); MirKeyboardAction action = mir_keyboard_event_action(key_event); QEvent::Type keyType = action == mir_keyboard_action_up ? QEvent::KeyRelease : QEvent::KeyPress; if (action == mir_keyboard_action_down) - mLastFocusedWindow = window; + mLastInputWindow = window; - char s[2]; - int sym = translateKeysym(xk_sym, s, sizeof(s)); - QString text = QString::fromLatin1(s); + QString text; + QVarLengthArray<char, 32> chars(32); + { + int result = xkb_keysym_to_utf8(xk_sym, chars.data(), chars.size()); + + if (result > 0) { + text = QString::fromUtf8(chars.constData()); + } + } + int sym = translateKeysym(xk_sym, text); bool is_auto_rep = action == mir_keyboard_action_repeat; QPlatformInputContext *context = QGuiApplicationPrivate::platformIntegration()->inputContext(); if (context) { - QKeyEvent qKeyEvent(keyType, sym, modifiers, text, is_auto_rep); + QKeyEvent qKeyEvent(keyType, sym, modifiers, scan_code, xk_sym, native_modifiers, text, is_auto_rep); qKeyEvent.setTimestamp(timestamp); if (context->filterEvent(&qKeyEvent)) { - DLOG("key event filtered out by input context"); + qCDebug(mirclient, "key event filtered out by input context"); return; } } - QWindowSystemInterface::handleKeyEvent(window->window(), timestamp, keyType, sym, modifiers, text, is_auto_rep); + QWindowSystemInterface::handleExtendedKeyEvent(window->window(), timestamp, keyType, sym, modifiers, scan_code, xk_sym, native_modifiers, text, is_auto_rep); } namespace @@ -481,14 +524,17 @@ Qt::MouseButtons extract_buttons(const MirPointerEvent *pev) void QMirClientInput::dispatchPointerEvent(QMirClientWindow *platformWindow, const MirInputEvent *ev) { - auto window = platformWindow->window(); - auto timestamp = mir_input_event_get_event_time(ev) / 1000000; + const auto window = platformWindow->window(); + const auto timestamp = mir_input_event_get_event_time(ev) / 1000000; + + const auto pev = mir_input_event_get_pointer_event(ev); + const auto action = mir_pointer_event_action(pev); + + const auto modifiers = qt_modifiers_from_mir(mir_pointer_event_modifiers(pev)); + const auto localPoint = QPointF(mir_pointer_event_axis_value(pev, mir_pointer_axis_x), + mir_pointer_event_axis_value(pev, mir_pointer_axis_y)); - auto pev = mir_input_event_get_pointer_event(ev); - auto action = mir_pointer_event_action(pev); - auto localPoint = QPointF(mir_pointer_event_axis_value(pev, mir_pointer_axis_x), - mir_pointer_event_axis_value(pev, mir_pointer_axis_y)); - auto modifiers = qt_modifiers_from_mir(mir_pointer_event_modifiers(pev)); + mLastInputWindow = platformWindow; switch (action) { case mir_pointer_action_button_up: @@ -499,7 +545,8 @@ void QMirClientInput::dispatchPointerEvent(QMirClientWindow *platformWindow, con const float vDelta = mir_pointer_event_axis_value(pev, mir_pointer_axis_vscroll); if (hDelta != 0 || vDelta != 0) { - const QPoint angleDelta = QPoint(hDelta * 15, vDelta * 15); + // QWheelEvent::DefaultDeltasPerStep = 120 but doesn't exist on vivid + const QPoint angleDelta(120 * hDelta, 120 * vDelta); QWindowSystemInterface::handleWheelEvent(window, timestamp, localPoint, window->position() + localPoint, QPoint(), angleDelta, modifiers, Qt::ScrollUpdate); } @@ -515,42 +562,32 @@ void QMirClientInput::dispatchPointerEvent(QMirClientWindow *platformWindow, con QWindowSystemInterface::handleLeaveEvent(window); break; default: - DLOG("Unrecognized pointer event"); + Q_UNREACHABLE(); } } -#if (LOG_EVENTS != 0) static const char* nativeOrientationDirectionToStr(MirOrientation orientation) { switch (orientation) { case mir_orientation_normal: return "Normal"; - break; case mir_orientation_left: return "Left"; - break; case mir_orientation_inverted: return "Inverted"; - break; case mir_orientation_right: return "Right"; - break; - default: - return "INVALID!"; } + Q_UNREACHABLE(); } -#endif void QMirClientInput::dispatchOrientationEvent(QWindow *window, const MirOrientationEvent *event) { MirOrientation mir_orientation = mir_orientation_event_get_direction(event); - #if (LOG_EVENTS != 0) - // Orientation event logging. - LOG("ORIENTATION direction: %s", nativeOrientationDirectionToStr(mir_orientation)); - #endif + qCDebug(mirclientInput, "orientation direction: %s", nativeOrientationDirectionToStr(mir_orientation)); if (!window->screen()) { - DLOG("Window has no associated screen, dropping orientation event"); + qCDebug(mirclient, "Window has no associated screen, dropping orientation event"); return; } @@ -569,7 +606,7 @@ void QMirClientInput::dispatchOrientationEvent(QWindow *window, const MirOrienta orientation = OrientationChangeEvent::RightUp; break; default: - DLOG("No such orientation %d", mir_orientation); + qCDebug(mirclient, "No such orientation %d", mir_orientation); return; } @@ -581,3 +618,61 @@ void QMirClientInput::dispatchOrientationEvent(QWindow *window, const MirOrienta new OrientationChangeEvent(OrientationChangeEvent::mType, orientation)); } +void QMirClientInput::handleSurfaceEvent(const QPointer<QMirClientWindow> &window, const MirSurfaceEvent *event) +{ + auto surfaceEventAttribute = mir_surface_event_get_attribute(event); + + switch (surfaceEventAttribute) { + case mir_surface_attrib_focus: { + window->handleSurfaceFocusChanged( + mir_surface_event_get_attribute_value(event) == mir_surface_focused); + break; + } + case mir_surface_attrib_visibility: { + window->handleSurfaceExposeChange( + mir_surface_event_get_attribute_value(event) == mir_surface_visibility_exposed); + break; + } + // Remaining attributes are ones client sets for server, and server should not override them + case mir_surface_attrib_state: { + MirSurfaceState state = static_cast<MirSurfaceState>(mir_surface_event_get_attribute_value(event)); + + if (state == mir_surface_state_hidden) { + window->handleSurfaceVisibilityChanged(false); + } else { + // it's visible! + window->handleSurfaceVisibilityChanged(true); + window->handleSurfaceStateChanged(mirSurfaceStateToWindowState(state)); + } + break; + } + case mir_surface_attrib_type: + case mir_surface_attrib_swapinterval: + case mir_surface_attrib_dpi: + case mir_surface_attrib_preferred_orientation: + case mir_surface_attribs: + break; + } +} + +void QMirClientInput::handleSurfaceOutputEvent(const QPointer<QMirClientWindow> &window, const MirSurfaceOutputEvent *event) +{ + const uint32_t outputId = mir_surface_output_event_get_output_id(event); + const int dpi = mir_surface_output_event_get_dpi(event); + const MirFormFactor formFactor = mir_surface_output_event_get_form_factor(event); + const float scale = mir_surface_output_event_get_scale(event); + + const auto screenObserver = mIntegration->screenObserver(); + QMirClientScreen *screen = screenObserver->findScreenWithId(outputId); + if (!screen) { + qCWarning(mirclient) << "Mir notified window" << window->window() << "on an unknown screen with id" << outputId; + return; + } + + screenObserver->handleScreenPropertiesChange(screen, dpi, formFactor, scale); + window->handleScreenPropertiesChange(formFactor, scale); + + if (window->screen() != screen) { + QWindowSystemInterface::handleWindowScreenChanged(window->window(), screen->screen()); + } +} diff --git a/src/plugins/platforms/mirclient/qmirclientinput.h b/src/plugins/platforms/mirclient/qmirclientinput.h index 3600ae7ece..263cb5e54e 100644 --- a/src/plugins/platforms/mirclient/qmirclientinput.h +++ b/src/plugins/platforms/mirclient/qmirclientinput.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2014-2015 Canonical, Ltd. +** Copyright (C) 2014-2016 Canonical, Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the plugins of the Qt Toolkit. @@ -43,7 +43,6 @@ // Qt #include <qpa/qwindowsysteminterface.h> -#include <QAtomicInt> #include <mir_toolkit/mir_client_library.h> @@ -63,7 +62,7 @@ public: void postEvent(QMirClientWindow* window, const MirEvent *event); QMirClientClientIntegration* integration() const { return mIntegration; } - QMirClientWindow *lastFocusedWindow() const {return mLastFocusedWindow; } + QMirClientWindow *lastInputWindow() const {return mLastInputWindow; } protected: void dispatchKeyEvent(QMirClientWindow *window, const MirInputEvent *event); @@ -72,6 +71,8 @@ protected: void dispatchInputEvent(QMirClientWindow *window, const MirInputEvent *event); void dispatchOrientationEvent(QWindow* window, const MirOrientationEvent *event); + void handleSurfaceEvent(const QPointer<QMirClientWindow> &window, const MirSurfaceEvent *event); + void handleSurfaceOutputEvent(const QPointer<QMirClientWindow> &window, const MirSurfaceOutputEvent *event); private: QMirClientClientIntegration* mIntegration; @@ -79,8 +80,7 @@ private: const QByteArray mEventFilterType; const QEvent::Type mEventType; - QMirClientWindow *mLastFocusedWindow; - QAtomicInt mPendingFocusGainedEvents; + QMirClientWindow *mLastInputWindow; }; #endif // QMIRCLIENTINPUT_H diff --git a/src/plugins/platforms/mirclient/qmirclientintegration.cpp b/src/plugins/platforms/mirclient/qmirclientintegration.cpp index 2c8740f070..eef96ee3de 100644 --- a/src/plugins/platforms/mirclient/qmirclientintegration.cpp +++ b/src/plugins/platforms/mirclient/qmirclientintegration.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2014-2015 Canonical, Ltd. +** Copyright (C) 2014-2016 Canonical, Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the plugins of the Qt Toolkit. @@ -42,6 +42,8 @@ #include "qmirclientintegration.h" #include "qmirclientbackingstore.h" #include "qmirclientclipboard.h" +#include "qmirclientdebugextension.h" +#include "qmirclientdesktopwindow.h" #include "qmirclientglcontext.h" #include "qmirclientinput.h" #include "qmirclientlogging.h" @@ -51,56 +53,62 @@ #include "qmirclientwindow.h" // Qt +#include <QFileInfo> #include <QGuiApplication> -#include <private/qguiapplication_p.h> #include <qpa/qplatformnativeinterface.h> #include <qpa/qplatforminputcontextfactory_p.h> #include <qpa/qplatforminputcontext.h> +#include <QtEglSupport/private/qeglconvenience_p.h> +#include <QtEglSupport/private/qeglpbuffer_p.h> #include <QtFontDatabaseSupport/private/qgenericunixfontdatabase_p.h> #include <QtEventDispatcherSupport/private/qgenericunixeventdispatcher_p.h> +#ifndef QT_NO_ACCESSIBILITY +#include <qpa/qplatformaccessibility.h> +#ifndef QT_NO_ACCESSIBILITY_ATSPI_BRIDGE +#include <QtLinuxAccessibilitySupport/private/bridge_p.h> +#endif +#endif + #include <QOpenGLContext> +#include <QOffscreenSurface> // platform-api #include <ubuntu/application/lifecycle_delegate.h> #include <ubuntu/application/id.h> #include <ubuntu/application/options.h> -static void resumedCallback(const UApplicationOptions *options, void* context) +static void resumedCallback(const UApplicationOptions */*options*/, void* context) { - Q_UNUSED(options) - Q_UNUSED(context) - DASSERT(context != NULL); - if (qGuiApp->focusWindow()) { - QWindowSystemInterface::handleApplicationStateChanged(Qt::ApplicationActive); - } else { - QWindowSystemInterface::handleApplicationStateChanged(Qt::ApplicationInactive); - } + auto integration = static_cast<QMirClientClientIntegration*>(context); + integration->appStateController()->setResumed(); } -static void aboutToStopCallback(UApplicationArchive *archive, void* context) +static void aboutToStopCallback(UApplicationArchive */*archive*/, void* context) { - Q_UNUSED(archive) - DASSERT(context != NULL); - QMirClientClientIntegration* integration = static_cast<QMirClientClientIntegration*>(context); - QPlatformInputContext *inputContext = integration->inputContext(); + auto integration = static_cast<QMirClientClientIntegration*>(context); + auto inputContext = integration->inputContext(); if (inputContext) { inputContext->hideInputPanel(); } else { - qWarning("QMirClientClientIntegration aboutToStopCallback(): no input context"); + qCWarning(mirclient) << "aboutToStopCallback(): no input context"; } - QWindowSystemInterface::handleApplicationStateChanged(Qt::ApplicationSuspended); + integration->appStateController()->setSuspended(); } -QMirClientClientIntegration::QMirClientClientIntegration() +QMirClientClientIntegration::QMirClientClientIntegration(int argc, char **argv) : QPlatformIntegration() - , mNativeInterface(new QMirClientNativeInterface) + , mNativeInterface(new QMirClientNativeInterface(this)) , mFontDb(new QGenericUnixFontDatabase) , mServices(new QMirClientPlatformServices) - , mClipboard(new QMirClientClipboard) + , mAppStateController(new QMirClientAppStateController) , mScaleFactor(1.0) { - setupOptions(); - setupDescription(); + { + QStringList args = QCoreApplication::arguments(); + setupOptions(args); + QByteArray sessionName = generateSessionName(args); + setupDescription(sessionName); + } // Create new application instance mInstance = u_application_instance_new_from_description_with_options(mDesc, mOptions); @@ -110,19 +118,48 @@ QMirClientClientIntegration::QMirClientClientIntegration() "running, and the correct socket is being used and is accessible. The shell may have\n" "rejected the incoming connection, so check its log file"); - mNativeInterface->setMirConnection(u_application_instance_get_mir_connection(mInstance)); + mMirConnection = u_application_instance_get_mir_connection(mInstance); + + // Choose the default surface format suited to the Mir platform + QSurfaceFormat defaultFormat; + defaultFormat.setRedBufferSize(8); + defaultFormat.setGreenBufferSize(8); + defaultFormat.setBlueBufferSize(8); + QSurfaceFormat::setDefaultFormat(defaultFormat); + + // Initialize EGL. + mEglNativeDisplay = mir_connection_get_egl_native_display(mMirConnection); + ASSERT((mEglDisplay = eglGetDisplay(mEglNativeDisplay)) != EGL_NO_DISPLAY); + ASSERT(eglInitialize(mEglDisplay, nullptr, nullptr) == EGL_TRUE); + + // Has debug mode been requsted, either with "-testability" switch or QT_LOAD_TESTABILITY env var + bool testability = qEnvironmentVariableIsSet("QT_LOAD_TESTABILITY"); + for (int i=1; !testability && i<argc; i++) { + if (strcmp(argv[i], "-testability") == 0) { + testability = true; + } + } + if (testability) { + mDebugExtension.reset(new QMirClientDebugExtension); + } +} - // Create default screen. - screenAdded(new QMirClientScreen(u_application_instance_get_mir_connection(mInstance))); +void QMirClientClientIntegration::initialize() +{ + // Init the ScreenObserver + mScreenObserver.reset(new QMirClientScreenObserver(mMirConnection)); + connect(mScreenObserver.data(), &QMirClientScreenObserver::screenAdded, + [this](QMirClientScreen *screen) { this->screenAdded(screen); }); + connect(mScreenObserver.data(), &QMirClientScreenObserver::screenRemoved, + this, &QMirClientClientIntegration::destroyScreen); + + Q_FOREACH (auto screen, mScreenObserver->screens()) { + screenAdded(screen); + } // Initialize input. - if (qEnvironmentVariableIsEmpty("QTUBUNTU_NO_INPUT")) { - mInput = new QMirClientInput(this); - mInputContext = QPlatformInputContextFactory::create(); - } else { - mInput = nullptr; - mInputContext = nullptr; - } + mInput = new QMirClientInput(this); + mInputContext = QPlatformInputContextFactory::create(); // compute the scale factor const int defaultGridUnit = 8; @@ -140,10 +177,9 @@ QMirClientClientIntegration::QMirClientClientIntegration() QMirClientClientIntegration::~QMirClientClientIntegration() { + eglTerminate(mEglDisplay); delete mInput; delete mInputContext; - for (QScreen *screen : QGuiApplication::screens()) - QPlatformIntegration::destroyScreen(screen->handle()); delete mServices; } @@ -152,9 +188,8 @@ QPlatformServices *QMirClientClientIntegration::services() const return mServices; } -void QMirClientClientIntegration::setupOptions() +void QMirClientClientIntegration::setupOptions(QStringList &args) { - QStringList args = QCoreApplication::arguments(); int argc = args.size() + 1; char **argv = new char*[argc]; for (int i = 0; i < argc - 1; i++) @@ -168,10 +203,11 @@ void QMirClientClientIntegration::setupOptions() delete [] argv; } -void QMirClientClientIntegration::setupDescription() +void QMirClientClientIntegration::setupDescription(QByteArray &sessionName) { mDesc = u_application_description_new(); - UApplicationId* id = u_application_id_new_from_stringn("QtUbuntu", 8); + + UApplicationId* id = u_application_id_new_from_stringn(sessionName.data(), sessionName.count()); u_application_description_set_application_id(mDesc, id); UApplicationLifecycleDelegate* delegate = u_application_lifecycle_delegate_new(); @@ -181,43 +217,66 @@ void QMirClientClientIntegration::setupDescription() u_application_description_set_application_lifecycle_delegate(mDesc, delegate); } -QPlatformWindow* QMirClientClientIntegration::createPlatformWindow(QWindow* window) const +QByteArray QMirClientClientIntegration::generateSessionName(QStringList &args) { - return const_cast<QMirClientClientIntegration*>(this)->createPlatformWindow(window); + // Try to come up with some meaningful session name to uniquely identify this session, + // helping with shell debugging + + if (args.count() == 0) { + return QByteArray("QtUbuntu"); + } if (args[0].contains("qmlscene")) { + return generateSessionNameFromQmlFile(args); + } else { + // use the executable name + QFileInfo fileInfo(args[0]); + return fileInfo.fileName().toLocal8Bit(); + } } -QPlatformWindow* QMirClientClientIntegration::createPlatformWindow(QWindow* window) +QByteArray QMirClientClientIntegration::generateSessionNameFromQmlFile(QStringList &args) { - return new QMirClientWindow(window, mClipboard, screen(), - mInput, u_application_instance_get_mir_connection(mInstance)); + Q_FOREACH (QString arg, args) { + if (arg.endsWith(".qml")) { + QFileInfo fileInfo(arg); + return fileInfo.fileName().toLocal8Bit(); + } + } + + // give up + return "qmlscene"; } -QMirClientScreen *QMirClientClientIntegration::screen() const +QPlatformWindow* QMirClientClientIntegration::createPlatformWindow(QWindow* window) const { - return static_cast<QMirClientScreen *>(QGuiApplication::primaryScreen()->handle()); + if (window->type() == Qt::Desktop) { + // Desktop windows should not be backed up by a mir surface as they don't draw anything (nor should). + return new QMirClientDesktopWindow(window); + } else { + return new QMirClientWindow(window, mInput, mNativeInterface, mAppStateController.data(), + mEglDisplay, mMirConnection, mDebugExtension.data()); + } } bool QMirClientClientIntegration::hasCapability(QPlatformIntegration::Capability cap) const { switch (cap) { - case ThreadedPixmaps: - return true; - - case OpenGL: - return true; - - case ApplicationState: - return true; - case ThreadedOpenGL: if (qEnvironmentVariableIsEmpty("QTUBUNTU_NO_THREADED_OPENGL")) { return true; } else { - DLOG("ubuntumirclient: disabled threaded OpenGL"); + qCDebug(mirclient, "disabled threaded OpenGL"); return false; } + + case ThreadedPixmaps: + case OpenGL: + case ApplicationState: case MultipleWindows: case NonFullScreenWindows: +#if QT_VERSION > QT_VERSION_CHECK(5, 5, 0) + case SwitchableWidgetComposition: +#endif + case RasterGLSurface: // needed for QQuickWidget return true; default: return QPlatformIntegration::hasCapability(cap); @@ -237,14 +296,25 @@ QPlatformBackingStore* QMirClientClientIntegration::createPlatformBackingStore(Q QPlatformOpenGLContext* QMirClientClientIntegration::createPlatformOpenGLContext( QOpenGLContext* context) const { - return const_cast<QMirClientClientIntegration*>(this)->createPlatformOpenGLContext(context); -} - -QPlatformOpenGLContext* QMirClientClientIntegration::createPlatformOpenGLContext( - QOpenGLContext* context) -{ - return new QMirClientOpenGLContext(static_cast<QMirClientScreen*>(context->screen()->handle()), - static_cast<QMirClientOpenGLContext*>(context->shareHandle())); + QSurfaceFormat format(context->format()); + + auto platformContext = new QMirClientOpenGLContext(format, context->shareHandle(), mEglDisplay); + if (!platformContext->isValid()) { + // Older Intel Atom-based devices only support OpenGL 1.4 compatibility profile but by default + // QML asks for at least OpenGL 2.0. The XCB GLX backend ignores this request and returns a + // 1.4 context, but the XCB EGL backend tries to honor it, and fails. The 1.4 context appears to + // have sufficient capabilities on MESA (i915) to render correctly however. So reduce the default + // requested OpenGL version to 1.0 to ensure EGL will give us a working context (lp:1549455). + static const bool isMesa = QString(eglQueryString(mEglDisplay, EGL_VENDOR)).contains(QStringLiteral("Mesa")); + if (isMesa) { + qCDebug(mirclientGraphics, "Attempting to choose OpenGL 1.4 context which may suit Mesa"); + format.setMajorVersion(1); + format.setMinorVersion(4); + delete platformContext; + platformContext = new QMirClientOpenGLContext(format, context->shareHandle(), mEglDisplay); + } + } + return platformContext; } QStringList QMirClientClientIntegration::themeNames() const @@ -277,10 +347,65 @@ QVariant QMirClientClientIntegration::styleHint(StyleHint hint) const QPlatformClipboard* QMirClientClientIntegration::clipboard() const { - return mClipboard.data(); + static QPlatformClipboard *clipboard = nullptr; + if (!clipboard) { + clipboard = new QMirClientClipboard; + } + return clipboard; } QPlatformNativeInterface* QMirClientClientIntegration::nativeInterface() const { return mNativeInterface; } + +QPlatformOffscreenSurface *QMirClientClientIntegration::createPlatformOffscreenSurface( + QOffscreenSurface *surface) const +{ + return new QEGLPbuffer(mEglDisplay, surface->requestedFormat(), surface); +} + +void QMirClientClientIntegration::destroyScreen(QMirClientScreen *screen) +{ + // FIXME: on deleting a screen while a Window is on it, Qt will automatically + // move the window to the primaryScreen(). This will trigger a screenChanged + // signal, causing things like QQuickScreenAttached to re-fetch screen properties + // like DPI and physical size. However this is crashing, as Qt is calling virtual + // functions on QPlatformScreen, for reasons unclear. As workaround, move window + // to primaryScreen() before deleting the screen. Might be QTBUG-38650 + + QScreen *primaryScreen = QGuiApplication::primaryScreen(); + if (screen != primaryScreen->handle()) { + uint32_t movedWindowCount = 0; + Q_FOREACH (QWindow *w, QGuiApplication::topLevelWindows()) { + if (w->screen()->handle() == screen) { + QWindowSystemInterface::handleWindowScreenChanged(w, primaryScreen); + ++movedWindowCount; + } + } + if (movedWindowCount > 0) { + QWindowSystemInterface::flushWindowSystemEvents(); + } + } + + qCDebug(mirclient) << "Removing Screen with id" << screen->mirOutputId() << "and geometry" << screen->geometry(); +#if QT_VERSION < QT_VERSION_CHECK(5, 5, 0) + delete screen; +#else + QPlatformIntegration::destroyScreen(screen); +#endif +} + +#ifndef QT_NO_ACCESSIBILITY +QPlatformAccessibility *QMirClientClientIntegration::accessibility() const +{ +#if !defined(QT_NO_ACCESSIBILITY_ATSPI_BRIDGE) + if (!mAccessibility) { + Q_ASSERT_X(QCoreApplication::eventDispatcher(), "QMirClientIntegration", + "Initializing accessibility without event-dispatcher!"); + mAccessibility.reset(new QSpiAccessibleBridge()); + } +#endif + return mAccessibility.data(); +} +#endif diff --git a/src/plugins/platforms/mirclient/qmirclientintegration.h b/src/plugins/platforms/mirclient/qmirclientintegration.h index 97317a310a..035117f4da 100644 --- a/src/plugins/platforms/mirclient/qmirclientintegration.h +++ b/src/plugins/platforms/mirclient/qmirclientintegration.h @@ -44,20 +44,28 @@ #include <qpa/qplatformintegration.h> #include <QSharedPointer> +#include "qmirclientappstatecontroller.h" #include "qmirclientplatformservices.h" +#include "qmirclientscreenobserver.h" // platform-api #include <ubuntu/application/description.h> #include <ubuntu/application/instance.h> -class QMirClientClipboard; +#include <EGL/egl.h> + +class QMirClientDebugExtension; class QMirClientInput; class QMirClientNativeInterface; class QMirClientScreen; +class MirConnection; + +class QMirClientClientIntegration : public QObject, public QPlatformIntegration +{ + Q_OBJECT -class QMirClientClientIntegration : public QPlatformIntegration { public: - QMirClientClientIntegration(); + QMirClientClientIntegration(int argc, char **argv); virtual ~QMirClientClientIntegration(); // QPlatformIntegration methods. @@ -74,14 +82,26 @@ public: QPlatformWindow* createPlatformWindow(QWindow* window) const override; QPlatformInputContext* inputContext() const override { return mInputContext; } QPlatformClipboard* clipboard() const override; + void initialize() override; + QPlatformOffscreenSurface *createPlatformOffscreenSurface(QOffscreenSurface *surface) const override; + QPlatformAccessibility *accessibility() const override; + + // New methods. + MirConnection *mirConnection() const { return mMirConnection; } + EGLDisplay eglDisplay() const { return mEglDisplay; } + EGLNativeDisplayType eglNativeDisplay() const { return mEglNativeDisplay; } + QMirClientAppStateController *appStateController() const { return mAppStateController.data(); } + QMirClientScreenObserver *screenObserver() const { return mScreenObserver.data(); } + QMirClientDebugExtension *debugExtension() const { return mDebugExtension.data(); } - QPlatformOpenGLContext* createPlatformOpenGLContext(QOpenGLContext* context); - QPlatformWindow* createPlatformWindow(QWindow* window); - QMirClientScreen* screen() const; +private Q_SLOTS: + void destroyScreen(QMirClientScreen *screen); private: - void setupOptions(); - void setupDescription(); + void setupOptions(QStringList &args); + void setupDescription(QByteArray &sessionName); + static QByteArray generateSessionName(QStringList &args); + static QByteArray generateSessionNameFromQmlFile(QStringList &args); QMirClientNativeInterface* mNativeInterface; QPlatformFontDatabase* mFontDb; @@ -90,13 +110,22 @@ private: QMirClientInput* mInput; QPlatformInputContext* mInputContext; - QSharedPointer<QMirClientClipboard> mClipboard; + mutable QScopedPointer<QPlatformAccessibility> mAccessibility; + QScopedPointer<QMirClientDebugExtension> mDebugExtension; + QScopedPointer<QMirClientScreenObserver> mScreenObserver; + QScopedPointer<QMirClientAppStateController> mAppStateController; qreal mScaleFactor; + MirConnection *mMirConnection; + // Platform API stuff UApplicationOptions* mOptions; UApplicationDescription* mDesc; UApplicationInstance* mInstance; + + // EGL related + EGLDisplay mEglDisplay{EGL_NO_DISPLAY}; + EGLNativeDisplayType mEglNativeDisplay; }; #endif // QMIRCLIENTINTEGRATION_H diff --git a/src/plugins/platforms/mirclient/qmirclientlogging.h b/src/plugins/platforms/mirclient/qmirclientlogging.h index 0eb3adbdc7..4921864ced 100644 --- a/src/plugins/platforms/mirclient/qmirclientlogging.h +++ b/src/plugins/platforms/mirclient/qmirclientlogging.h @@ -41,23 +41,15 @@ #ifndef QMIRCLIENTLOGGING_H #define QMIRCLIENTLOGGING_H -// Logging and assertion macros. -#define LOG(...) qDebug(__VA_ARGS__) -#define LOG_IF(cond,...) do { if (cond) qDebug(__VA_ARGS__); } while (0) +#include <QLoggingCategory> + #define ASSERT(cond) ((!(cond)) ? qt_assert(#cond,__FILE__,__LINE__) : qt_noop()) -#define NOT_REACHED() qt_assert("Not reached!",__FILE__,__LINE__) -// Logging and assertion macros are compiled out for release builds. -#if !defined(QT_NO_DEBUG) -#define DLOG(...) LOG(__VA_ARGS__) -#define DLOG_IF(cond,...) LOG_IF((cond), __VA_ARGS__) -#define DASSERT(cond) ASSERT((cond)) -#define DNOT_REACHED() NOT_REACHED() -#else -#define DLOG(...) qt_noop() -#define DLOG_IF(cond,...) qt_noop() -#define DASSERT(cond) qt_noop() -#define DNOT_REACHED() qt_noop() -#endif +Q_DECLARE_LOGGING_CATEGORY(mirclient) +Q_DECLARE_LOGGING_CATEGORY(mirclientBufferSwap) +Q_DECLARE_LOGGING_CATEGORY(mirclientInput) +Q_DECLARE_LOGGING_CATEGORY(mirclientGraphics) +Q_DECLARE_LOGGING_CATEGORY(mirclientCursor) +Q_DECLARE_LOGGING_CATEGORY(mirclientDebug) #endif // QMIRCLIENTLOGGING_H diff --git a/src/plugins/platforms/mirclient/qmirclientnativeinterface.cpp b/src/plugins/platforms/mirclient/qmirclientnativeinterface.cpp index 033df6ba11..b85e6fedfa 100644 --- a/src/plugins/platforms/mirclient/qmirclientnativeinterface.cpp +++ b/src/plugins/platforms/mirclient/qmirclientnativeinterface.cpp @@ -42,32 +42,36 @@ #include "qmirclientnativeinterface.h" #include "qmirclientscreen.h" #include "qmirclientglcontext.h" +#include "qmirclientwindow.h" // Qt -#include <private/qguiapplication_p.h> +#include <QtGui/private/qguiapplication_p.h> #include <QtGui/qopenglcontext.h> #include <QtGui/qscreen.h> #include <QtCore/QMap> -class QMirClientResourceMap : public QMap<QByteArray, QMirClientNativeInterface::ResourceType> +class UbuntuResourceMap : public QMap<QByteArray, QMirClientNativeInterface::ResourceType> { public: - QMirClientResourceMap() + UbuntuResourceMap() : QMap<QByteArray, QMirClientNativeInterface::ResourceType>() { insert("egldisplay", QMirClientNativeInterface::EglDisplay); insert("eglcontext", QMirClientNativeInterface::EglContext); insert("nativeorientation", QMirClientNativeInterface::NativeOrientation); insert("display", QMirClientNativeInterface::Display); insert("mirconnection", QMirClientNativeInterface::MirConnection); + insert("mirsurface", QMirClientNativeInterface::MirSurface); + insert("scale", QMirClientNativeInterface::Scale); + insert("formfactor", QMirClientNativeInterface::FormFactor); } }; -Q_GLOBAL_STATIC(QMirClientResourceMap, ubuntuResourceMap) +Q_GLOBAL_STATIC(UbuntuResourceMap, ubuntuResourceMap) -QMirClientNativeInterface::QMirClientNativeInterface() - : mGenericEventFilterType(QByteArrayLiteral("Event")) +QMirClientNativeInterface::QMirClientNativeInterface(const QMirClientClientIntegration *integration) + : mIntegration(integration) + , mGenericEventFilterType(QByteArrayLiteral("Event")) , mNativeOrientation(nullptr) - , mMirConnection(nullptr) { } @@ -88,7 +92,7 @@ void* QMirClientNativeInterface::nativeResourceForIntegration(const QByteArray & const ResourceType resourceType = ubuntuResourceMap()->value(lowerCaseResource); if (resourceType == QMirClientNativeInterface::MirConnection) { - return mMirConnection; + return mIntegration->mirConnection(); } else { return nullptr; } @@ -119,14 +123,11 @@ void* QMirClientNativeInterface::nativeResourceForWindow(const QByteArray& resou if (!ubuntuResourceMap()->contains(kLowerCaseResource)) return NULL; const ResourceType kResourceType = ubuntuResourceMap()->value(kLowerCaseResource); - if (kResourceType == QMirClientNativeInterface::EglDisplay) { - if (window) { - return static_cast<QMirClientScreen*>(window->screen()->handle())->eglDisplay(); - } else { - return static_cast<QMirClientScreen*>( - QGuiApplication::primaryScreen()->handle())->eglDisplay(); - } - } else if (kResourceType == QMirClientNativeInterface::NativeOrientation) { + + switch (kResourceType) { + case EglDisplay: + return mIntegration->eglDisplay(); + case NativeOrientation: // Return the device's native screen orientation. if (window) { QMirClientScreen *ubuntuScreen = static_cast<QMirClientScreen*>(window->screen()->handle()); @@ -136,8 +137,19 @@ void* QMirClientNativeInterface::nativeResourceForWindow(const QByteArray& resou mNativeOrientation = new Qt::ScreenOrientation(platformScreen->nativeOrientation()); } return mNativeOrientation; - } else { - return NULL; + case MirSurface: + if (window) { + auto ubuntuWindow = static_cast<QMirClientWindow*>(window->handle()); + if (ubuntuWindow) { + return ubuntuWindow->mirSurface(); + } else { + return nullptr; + } + } else { + return nullptr; + } + default: + return nullptr; } } @@ -147,10 +159,59 @@ void* QMirClientNativeInterface::nativeResourceForScreen(const QByteArray& resou if (!ubuntuResourceMap()->contains(kLowerCaseResource)) return NULL; const ResourceType kResourceType = ubuntuResourceMap()->value(kLowerCaseResource); + if (!screen) + screen = QGuiApplication::primaryScreen(); + auto ubuntuScreen = static_cast<QMirClientScreen*>(screen->handle()); if (kResourceType == QMirClientNativeInterface::Display) { - if (!screen) - screen = QGuiApplication::primaryScreen(); - return static_cast<QMirClientScreen*>(screen->handle())->eglNativeDisplay(); + return mIntegration->eglNativeDisplay(); + // Changes to the following properties are emitted via the QMirClientNativeInterface::screenPropertyChanged + // signal fired by QMirClientScreen. Connect to this signal for these properties updates. + // WARNING: code highly thread unsafe! + } else if (kResourceType == QMirClientNativeInterface::Scale) { + // In application code, read with: + // float scale = *reinterpret_cast<float*>(nativeResourceForScreen("scale", screen())); + return &ubuntuScreen->mScale; + } else if (kResourceType == QMirClientNativeInterface::FormFactor) { + return &ubuntuScreen->mFormFactor; } else return NULL; } + +// Changes to these properties are emitted via the QMirClientNativeInterface::windowPropertyChanged +// signal fired by QMirClientWindow. Connect to this signal for these properties updates. +QVariantMap QMirClientNativeInterface::windowProperties(QPlatformWindow *window) const +{ + QVariantMap propertyMap; + auto w = static_cast<QMirClientWindow*>(window); + if (w) { + propertyMap.insert("scale", w->scale()); + propertyMap.insert("formFactor", w->formFactor()); + } + return propertyMap; +} + +QVariant QMirClientNativeInterface::windowProperty(QPlatformWindow *window, const QString &name) const +{ + auto w = static_cast<QMirClientWindow*>(window); + if (!w) { + return QVariant(); + } + + if (name == QStringLiteral("scale")) { + return w->scale(); + } else if (name == QStringLiteral("formFactor")) { + return w->formFactor(); + } else { + return QVariant(); + } +} + +QVariant QMirClientNativeInterface::windowProperty(QPlatformWindow *window, const QString &name, const QVariant &defaultValue) const +{ + QVariant returnVal = windowProperty(window, name); + if (!returnVal.isValid()) { + return defaultValue; + } else { + return returnVal; + } +} diff --git a/src/plugins/platforms/mirclient/qmirclientnativeinterface.h b/src/plugins/platforms/mirclient/qmirclientnativeinterface.h index 78a440e956..eb601de301 100644 --- a/src/plugins/platforms/mirclient/qmirclientnativeinterface.h +++ b/src/plugins/platforms/mirclient/qmirclientnativeinterface.h @@ -43,11 +43,16 @@ #include <qpa/qplatformnativeinterface.h> +#include "qmirclientintegration.h" + +class QPlatformScreen; + class QMirClientNativeInterface : public QPlatformNativeInterface { + Q_OBJECT public: - enum ResourceType { EglDisplay, EglContext, NativeOrientation, Display, MirConnection }; + enum ResourceType { EglDisplay, EglContext, NativeOrientation, Display, MirConnection, MirSurface, Scale, FormFactor }; - QMirClientNativeInterface(); + QMirClientNativeInterface(const QMirClientClientIntegration *integration); ~QMirClientNativeInterface(); // QPlatformNativeInterface methods. @@ -59,14 +64,20 @@ public: void* nativeResourceForScreen(const QByteArray& resourceString, QScreen* screen) override; + QVariantMap windowProperties(QPlatformWindow *window) const override; + QVariant windowProperty(QPlatformWindow *window, const QString &name) const override; + QVariant windowProperty(QPlatformWindow *window, const QString &name, const QVariant &defaultValue) const override; + // New methods. const QByteArray& genericEventFilterType() const { return mGenericEventFilterType; } - void setMirConnection(void *mirConnection) { mMirConnection = mirConnection; } + +Q_SIGNALS: // New signals + void screenPropertyChanged(QPlatformScreen *screen, const QString &propertyName); private: + const QMirClientClientIntegration *mIntegration; const QByteArray mGenericEventFilterType; Qt::ScreenOrientation* mNativeOrientation; - void *mMirConnection; }; #endif // QMIRCLIENTNATIVEINTERFACE_H diff --git a/src/plugins/platforms/mirclient/qmirclientplugin.cpp b/src/plugins/platforms/mirclient/qmirclientplugin.cpp index 6899d70f2e..fc44edfe40 100644 --- a/src/plugins/platforms/mirclient/qmirclientplugin.cpp +++ b/src/plugins/platforms/mirclient/qmirclientplugin.cpp @@ -40,12 +40,16 @@ #include "qmirclientplugin.h" #include "qmirclientintegration.h" +#include "qmirclientlogging.h" -QPlatformIntegration* QMirClientIntegrationPlugin::create(const QString &system, - const QStringList &) +Q_LOGGING_CATEGORY(mirclient, "qt.qpa.mirclient", QtWarningMsg) + +QPlatformIntegration *QMirClientIntegrationPlugin::create(const QString &system, + const QStringList &/*paramList*/, + int &argc, char **argv) { if (system.toLower() == QLatin1String("mirclient")) { - return new QMirClientClientIntegration; + return new QMirClientClientIntegration(argc, argv); } else { return 0; } diff --git a/src/plugins/platforms/mirclient/qmirclientplugin.h b/src/plugins/platforms/mirclient/qmirclientplugin.h index c91f2d1924..207d97b5af 100644 --- a/src/plugins/platforms/mirclient/qmirclientplugin.h +++ b/src/plugins/platforms/mirclient/qmirclientplugin.h @@ -49,7 +49,8 @@ class QMirClientIntegrationPlugin : public QPlatformIntegrationPlugin Q_PLUGIN_METADATA(IID QPlatformIntegrationFactoryInterface_iid FILE "mirclient.json") public: - QPlatformIntegration* create(const QString&, const QStringList&); + QPlatformIntegration *create(const QString &system, const QStringList ¶mList, + int &argc, char **argv) override; }; #endif // QMIRCLIENTPLUGIN_H diff --git a/src/plugins/platforms/mirclient/qmirclientscreen.cpp b/src/plugins/platforms/mirclient/qmirclientscreen.cpp index 0a2253e9e2..cc8db830aa 100644 --- a/src/plugins/platforms/mirclient/qmirclientscreen.cpp +++ b/src/plugins/platforms/mirclient/qmirclientscreen.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2014-2015 Canonical, Ltd. +** Copyright (C) 2014-2016 Canonical, Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the plugins of the Qt Toolkit. @@ -42,11 +42,12 @@ #include "qmirclientscreen.h" #include "qmirclientlogging.h" #include "qmirclientorientationchangeevent_p.h" +#include "qmirclientnativeinterface.h" #include <mir_toolkit/mir_client_library.h> // Qt -#include <QCoreApplication> +#include <QGuiApplication> #include <QtCore/qmath.h> #include <QScreen> #include <QThread> @@ -55,9 +56,7 @@ #include <memory> -static const int kSwapInterval = 1; - -#if !defined(QT_NO_DEBUG) +static const int overrideDevicePixelRatio = qgetenv("QT_DEVICE_PIXEL_RATIO").toInt(); static const char *orientationToStr(Qt::ScreenOrientation orientation) { switch (orientation) { @@ -71,173 +70,33 @@ static const char *orientationToStr(Qt::ScreenOrientation orientation) { return "inverted portrait"; case Qt::InvertedLandscapeOrientation: return "inverted landscape"; - default: - return "INVALID!"; } + Q_UNREACHABLE(); } -static void printEglConfig(EGLDisplay display, EGLConfig config) { - DASSERT(display != EGL_NO_DISPLAY); - DASSERT(config != nullptr); - static const struct { const EGLint attrib; const char* name; } kAttribs[] = { - { EGL_BUFFER_SIZE, "EGL_BUFFER_SIZE" }, - { EGL_ALPHA_SIZE, "EGL_ALPHA_SIZE" }, - { EGL_BLUE_SIZE, "EGL_BLUE_SIZE" }, - { EGL_GREEN_SIZE, "EGL_GREEN_SIZE" }, - { EGL_RED_SIZE, "EGL_RED_SIZE" }, - { EGL_DEPTH_SIZE, "EGL_DEPTH_SIZE" }, - { EGL_STENCIL_SIZE, "EGL_STENCIL_SIZE" }, - { EGL_CONFIG_CAVEAT, "EGL_CONFIG_CAVEAT" }, - { EGL_CONFIG_ID, "EGL_CONFIG_ID" }, - { EGL_LEVEL, "EGL_LEVEL" }, - { EGL_MAX_PBUFFER_HEIGHT, "EGL_MAX_PBUFFER_HEIGHT" }, - { EGL_MAX_PBUFFER_PIXELS, "EGL_MAX_PBUFFER_PIXELS" }, - { EGL_MAX_PBUFFER_WIDTH, "EGL_MAX_PBUFFER_WIDTH" }, - { EGL_NATIVE_RENDERABLE, "EGL_NATIVE_RENDERABLE" }, - { EGL_NATIVE_VISUAL_ID, "EGL_NATIVE_VISUAL_ID" }, - { EGL_NATIVE_VISUAL_TYPE, "EGL_NATIVE_VISUAL_TYPE" }, - { EGL_SAMPLES, "EGL_SAMPLES" }, - { EGL_SAMPLE_BUFFERS, "EGL_SAMPLE_BUFFERS" }, - { EGL_SURFACE_TYPE, "EGL_SURFACE_TYPE" }, - { EGL_TRANSPARENT_TYPE, "EGL_TRANSPARENT_TYPE" }, - { EGL_TRANSPARENT_BLUE_VALUE, "EGL_TRANSPARENT_BLUE_VALUE" }, - { EGL_TRANSPARENT_GREEN_VALUE, "EGL_TRANSPARENT_GREEN_VALUE" }, - { EGL_TRANSPARENT_RED_VALUE, "EGL_TRANSPARENT_RED_VALUE" }, - { EGL_BIND_TO_TEXTURE_RGB, "EGL_BIND_TO_TEXTURE_RGB" }, - { EGL_BIND_TO_TEXTURE_RGBA, "EGL_BIND_TO_TEXTURE_RGBA" }, - { EGL_MIN_SWAP_INTERVAL, "EGL_MIN_SWAP_INTERVAL" }, - { EGL_MAX_SWAP_INTERVAL, "EGL_MAX_SWAP_INTERVAL" }, - { -1, NULL } - }; - const char* string = eglQueryString(display, EGL_VENDOR); - LOG("EGL vendor: %s", string); - string = eglQueryString(display, EGL_VERSION); - LOG("EGL version: %s", string); - string = eglQueryString(display, EGL_EXTENSIONS); - LOG("EGL extensions: %s", string); - LOG("EGL configuration attibutes:"); - for (int index = 0; kAttribs[index].attrib != -1; index++) { - EGLint value; - if (eglGetConfigAttrib(display, config, kAttribs[index].attrib, &value)) - LOG(" %s: %d", kAttribs[index].name, static_cast<int>(value)); - } -} -#endif - - const QEvent::Type OrientationChangeEvent::mType = static_cast<QEvent::Type>(QEvent::registerEventType()); -static const MirDisplayOutput *find_active_output( - const MirDisplayConfiguration *conf) -{ - const MirDisplayOutput *output = NULL; - for (uint32_t d = 0; d < conf->num_outputs; d++) - { - const MirDisplayOutput *out = conf->outputs + d; - - if (out->used && - out->connected && - out->num_modes && - out->current_mode < out->num_modes) - { - output = out; - break; - } - } - - return output; -} -QMirClientScreen::QMirClientScreen(MirConnection *connection) - : mFormat(QImage::Format_RGB32) +QMirClientScreen::QMirClientScreen(const MirOutput *output, MirConnection *connection) + : mDevicePixelRatio(1.0) + , mFormat(QImage::Format_RGB32) , mDepth(32) + , mDpi{0} + , mFormFactor{mir_form_factor_unknown} + , mScale{1.0} , mOutputId(0) - , mSurfaceFormat() - , mEglDisplay(EGL_NO_DISPLAY) - , mEglConfig(nullptr) , mCursor(connection) { - // Initialize EGL. - ASSERT(eglBindAPI(EGL_OPENGL_ES_API) == EGL_TRUE); - - mEglNativeDisplay = mir_connection_get_egl_native_display(connection); - ASSERT((mEglDisplay = eglGetDisplay(mEglNativeDisplay)) != EGL_NO_DISPLAY); - ASSERT(eglInitialize(mEglDisplay, nullptr, nullptr) == EGL_TRUE); - - // Configure EGL buffers format. - mSurfaceFormat.setRedBufferSize(8); - mSurfaceFormat.setGreenBufferSize(8); - mSurfaceFormat.setBlueBufferSize(8); - mSurfaceFormat.setAlphaBufferSize(8); - mSurfaceFormat.setDepthBufferSize(24); - mSurfaceFormat.setStencilBufferSize(8); - if (!qEnvironmentVariableIsEmpty("QTUBUNTU_MULTISAMPLE")) { - mSurfaceFormat.setSamples(4); - DLOG("ubuntumirclient: setting MSAA to 4 samples"); - } -#ifdef QTUBUNTU_USE_OPENGL - mSurfaceFormat.setRenderableType(QSurfaceFormat::OpenGL); -#else - mSurfaceFormat.setRenderableType(QSurfaceFormat::OpenGLES); -#endif - mEglConfig = q_configFromGLFormat(mEglDisplay, mSurfaceFormat, true); - - #if !defined(QT_NO_DEBUG) - printEglConfig(mEglDisplay, mEglConfig); - #endif - - // Set vblank swap interval. - int swapInterval = kSwapInterval; - QByteArray swapIntervalString = qgetenv("QTUBUNTU_SWAPINTERVAL"); - if (!swapIntervalString.isEmpty()) { - bool ok; - swapInterval = swapIntervalString.toInt(&ok); - if (!ok) - swapInterval = kSwapInterval; - } - DLOG("ubuntumirclient: setting swap interval to %d", swapInterval); - eglSwapInterval(mEglDisplay, swapInterval); - - // Get screen resolution. - auto configDeleter = [](MirDisplayConfiguration *config) { mir_display_config_destroy(config); }; - using configUp = std::unique_ptr<MirDisplayConfiguration, decltype(configDeleter)>; - configUp displayConfig(mir_connection_create_display_config(connection), configDeleter); - ASSERT(displayConfig != nullptr); - - auto const displayOutput = find_active_output(displayConfig.get()); - ASSERT(displayOutput != nullptr); - - mOutputId = displayOutput->output_id; - - mPhysicalSize = QSizeF(displayOutput->physical_width_mm, displayOutput->physical_height_mm); - DLOG("ubuntumirclient: screen physical size: %.2fx%.2f", mPhysicalSize.width(), mPhysicalSize.height()); - - const MirDisplayMode *mode = &displayOutput->modes[displayOutput->current_mode]; - const int kScreenWidth = mode->horizontal_resolution; - const int kScreenHeight = mode->vertical_resolution; - DASSERT(kScreenWidth > 0 && kScreenHeight > 0); - - DLOG("ubuntumirclient: screen resolution: %dx%d", kScreenWidth, kScreenHeight); - - mGeometry = QRect(0, 0, kScreenWidth, kScreenHeight); - - DLOG("QQMirClientScreen::QQMirClientScreen (this=%p)", this); - - // Set the default orientation based on the initial screen dimmensions. - mNativeOrientation = (mGeometry.width() >= mGeometry.height()) ? Qt::LandscapeOrientation : Qt::PortraitOrientation; - - // If it's a landscape device (i.e. some tablets), start in landscape, otherwise portrait - mCurrentOrientation = (mNativeOrientation == Qt::LandscapeOrientation) ? Qt::LandscapeOrientation : Qt::PortraitOrientation; + setMirOutput(output); } QMirClientScreen::~QMirClientScreen() { - eglTerminate(mEglDisplay); } void QMirClientScreen::customEvent(QEvent* event) { - DASSERT(QThread::currentThread() == thread()); + Q_ASSERT(QThread::currentThread() == thread()); OrientationChangeEvent* oReadingEvent = static_cast<OrientationChangeEvent*>(event); switch (oReadingEvent->mOrientation) { @@ -261,14 +120,10 @@ void QMirClientScreen::customEvent(QEvent* event) { Qt::InvertedLandscapeOrientation : Qt::InvertedPortraitOrientation; break; } - default: { - DLOG("QMirClientScreen::customEvent - Unknown orientation."); - return; - } } // Raise the event signal so that client apps know the orientation changed - DLOG("QMirClientScreen::customEvent - handling orientation change to %s", orientationToStr(mCurrentOrientation)); + qCDebug(mirclient, "QMirClientScreen::customEvent - handling orientation change to %s", orientationToStr(mCurrentOrientation)); QWindowSystemInterface::handleScreenOrientationChange(screen(), mCurrentOrientation); } @@ -289,7 +144,7 @@ void QMirClientScreen::handleWindowSurfaceResize(int windowWidth, int windowHeig mGeometry.setWidth(currGeometry.height()); mGeometry.setHeight(currGeometry.width()); - DLOG("QMirClientScreen::handleWindowSurfaceResize - new screen geometry (w=%d, h=%d)", + qCDebug(mirclient, "QMirClientScreen::handleWindowSurfaceResize - new screen geometry (w=%d, h=%d)", mGeometry.width(), mGeometry.height()); QWindowSystemInterface::handleScreenGeometryChange(screen(), mGeometry /* newGeometry */, @@ -300,7 +155,108 @@ void QMirClientScreen::handleWindowSurfaceResize(int windowWidth, int windowHeig } else { mCurrentOrientation = Qt::LandscapeOrientation; } - DLOG("QMirClientScreen::handleWindowSurfaceResize - new orientation %s",orientationToStr(mCurrentOrientation)); + qCDebug(mirclient, "QMirClientScreen::handleWindowSurfaceResize - new orientation %s",orientationToStr(mCurrentOrientation)); QWindowSystemInterface::handleScreenOrientationChange(screen(), mCurrentOrientation); } } + +void QMirClientScreen::setMirOutput(const MirOutput *output) +{ + // Physical screen size (in mm) + mPhysicalSize.setWidth(mir_output_get_physical_width_mm(output)); + mPhysicalSize.setHeight(mir_output_get_physical_height_mm(output)); + + // Pixel Format +// mFormat = qImageFormatFromMirPixelFormat(mir_output_get_current_pixel_format(output)); // GERRY: TODO + + // Pixel depth + mDepth = 8 * MIR_BYTES_PER_PIXEL(mir_output_get_current_pixel_format(output)); + + // Mode = Resolution & refresh rate + const MirOutputMode *mode = mir_output_get_current_mode(output); + mNativeGeometry.setX(mir_output_get_position_x(output)); + mNativeGeometry.setY(mir_output_get_position_y(output)); + mNativeGeometry.setWidth(mir_output_mode_get_width(mode)); + mNativeGeometry.setHeight(mir_output_mode_get_height(mode)); + + mRefreshRate = mir_output_mode_get_refresh_rate(mode); + + // UI scale & DPR + mScale = mir_output_get_scale_factor(output); + if (overrideDevicePixelRatio > 0) { + mDevicePixelRatio = overrideDevicePixelRatio; + } else { + mDevicePixelRatio = 1.0; // FIXME - need to determine suitable DPR for the specified scale + } + + mFormFactor = mir_output_get_form_factor(output); + + mOutputId = mir_output_get_id(output); + + mGeometry.setX(mNativeGeometry.x()); + mGeometry.setY(mNativeGeometry.y()); + mGeometry.setWidth(mNativeGeometry.width()); + mGeometry.setHeight(mNativeGeometry.height()); + + // Set the default orientation based on the initial screen dimensions. + mNativeOrientation = (mGeometry.width() >= mGeometry.height()) ? Qt::LandscapeOrientation : Qt::PortraitOrientation; + + // If it's a landscape device (i.e. some tablets), start in landscape, otherwise portrait + mCurrentOrientation = (mNativeOrientation == Qt::LandscapeOrientation) ? Qt::LandscapeOrientation : Qt::PortraitOrientation; +} + +void QMirClientScreen::updateMirOutput(const MirOutput *output) +{ + auto oldRefreshRate = mRefreshRate; + auto oldScale = mScale; + auto oldFormFactor = mFormFactor; + auto oldGeometry = mGeometry; + + setMirOutput(output); + + // Emit change signals in particular order + if (oldGeometry != mGeometry) { + QWindowSystemInterface::handleScreenGeometryChange(screen(), + mGeometry /* newGeometry */, + mGeometry /* newAvailableGeometry */); + } + + if (!qFuzzyCompare(mRefreshRate, oldRefreshRate)) { + QWindowSystemInterface::handleScreenRefreshRateChange(screen(), mRefreshRate); + } + + auto nativeInterface = static_cast<QMirClientNativeInterface *>(qGuiApp->platformNativeInterface()); + if (!qFuzzyCompare(mScale, oldScale)) { + nativeInterface->screenPropertyChanged(this, QStringLiteral("scale")); + } + if (mFormFactor != oldFormFactor) { + nativeInterface->screenPropertyChanged(this, QStringLiteral("formFactor")); + } +} + +void QMirClientScreen::setAdditionalMirDisplayProperties(float scale, MirFormFactor formFactor, int dpi) +{ + if (mDpi != dpi) { + mDpi = dpi; + QWindowSystemInterface::handleScreenLogicalDotsPerInchChange(screen(), dpi, dpi); + } + + auto nativeInterface = static_cast<QMirClientNativeInterface *>(qGuiApp->platformNativeInterface()); + if (!qFuzzyCompare(mScale, scale)) { + mScale = scale; + nativeInterface->screenPropertyChanged(this, QStringLiteral("scale")); + } + if (mFormFactor != formFactor) { + mFormFactor = formFactor; + nativeInterface->screenPropertyChanged(this, QStringLiteral("formFactor")); + } +} + +QDpi QMirClientScreen::logicalDpi() const +{ + if (mDpi > 0) { + return QDpi(mDpi, mDpi); + } else { + return QPlatformScreen::logicalDpi(); + } +} diff --git a/src/plugins/platforms/mirclient/qmirclientscreen.h b/src/plugins/platforms/mirclient/qmirclientscreen.h index b050836ada..b31cba1964 100644 --- a/src/plugins/platforms/mirclient/qmirclientscreen.h +++ b/src/plugins/platforms/mirclient/qmirclientscreen.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2014-2015 Canonical, Ltd. +** Copyright (C) 2014-2016 Canonical, Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the plugins of the Qt Toolkit. @@ -43,17 +43,19 @@ #include <qpa/qplatformscreen.h> #include <QSurfaceFormat> -#include <EGL/egl.h> + +#include <mir_toolkit/common.h> // just for MirFormFactor enum #include "qmirclientcursor.h" struct MirConnection; +struct MirOutput; class QMirClientScreen : public QObject, public QPlatformScreen { Q_OBJECT public: - QMirClientScreen(MirConnection *connection); + QMirClientScreen(const MirOutput *output, MirConnection *connection); virtual ~QMirClientScreen(); // QPlatformScreen methods. @@ -62,34 +64,43 @@ public: QRect geometry() const override { return mGeometry; } QRect availableGeometry() const override { return mGeometry; } QSizeF physicalSize() const override { return mPhysicalSize; } + qreal devicePixelRatio() const override { return mDevicePixelRatio; } + QDpi logicalDpi() const override; Qt::ScreenOrientation nativeOrientation() const override { return mNativeOrientation; } Qt::ScreenOrientation orientation() const override { return mNativeOrientation; } QPlatformCursor *cursor() const override { return const_cast<QMirClientCursor*>(&mCursor); } - // New methods. - QSurfaceFormat surfaceFormat() const { return mSurfaceFormat; } - EGLDisplay eglDisplay() const { return mEglDisplay; } - EGLConfig eglConfig() const { return mEglConfig; } - EGLNativeDisplayType eglNativeDisplay() const { return mEglNativeDisplay; } + // Additional Screen properties from Mir + int mirOutputId() const { return mOutputId; } + MirFormFactor formFactor() const { return mFormFactor; } + float scale() const { return mScale; } + + // Internally used methods + void updateMirOutput(const MirOutput *output); + void setAdditionalMirDisplayProperties(float scale, MirFormFactor formFactor, int dpi); void handleWindowSurfaceResize(int width, int height); - uint32_t mirOutputId() const { return mOutputId; } // QObject methods. void customEvent(QEvent* event) override; private: - QRect mGeometry; + void setMirOutput(const MirOutput *output); + + QRect mGeometry, mNativeGeometry; QSizeF mPhysicalSize; + qreal mDevicePixelRatio; Qt::ScreenOrientation mNativeOrientation; Qt::ScreenOrientation mCurrentOrientation; QImage::Format mFormat; int mDepth; - uint32_t mOutputId; - QSurfaceFormat mSurfaceFormat; - EGLDisplay mEglDisplay; - EGLConfig mEglConfig; - EGLNativeDisplayType mEglNativeDisplay; + int mDpi; + qreal mRefreshRate; + MirFormFactor mFormFactor; + float mScale; + int mOutputId; QMirClientCursor mCursor; + + friend class QMirClientNativeInterface; }; #endif // QMIRCLIENTSCREEN_H diff --git a/src/plugins/platforms/mirclient/qmirclientscreenobserver.cpp b/src/plugins/platforms/mirclient/qmirclientscreenobserver.cpp new file mode 100644 index 0000000000..792aeca351 --- /dev/null +++ b/src/plugins/platforms/mirclient/qmirclientscreenobserver.cpp @@ -0,0 +1,161 @@ +/**************************************************************************** +** +** Copyright (C) 2016 Canonical, Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include "qmirclientscreenobserver.h" +#include "qmirclientscreen.h" +#include "qmirclientwindow.h" +#include "qmirclientlogging.h" + +// Qt +#include <QMetaObject> +#include <QPointer> + +// Mir +#include <mirclient/mir_toolkit/mir_connection.h> +#include <mirclient/mir_toolkit/mir_display_configuration.h> + +#include <memory> + +namespace { + static void displayConfigurationChangedCallback(MirConnection */*connection*/, void* context) + { + ASSERT(context != NULL); + QMirClientScreenObserver *observer = static_cast<QMirClientScreenObserver *>(context); + QMetaObject::invokeMethod(observer, "update"); + } + + const char *mirFormFactorToStr(MirFormFactor formFactor) + { + switch (formFactor) { + case mir_form_factor_unknown: return "unknown"; + case mir_form_factor_phone: return "phone"; + case mir_form_factor_tablet: return "tablet"; + case mir_form_factor_monitor: return "monitor"; + case mir_form_factor_tv: return "tv"; + case mir_form_factor_projector: return "projector"; + } + Q_UNREACHABLE(); + } +} // anonymous namespace + +QMirClientScreenObserver::QMirClientScreenObserver(MirConnection *mirConnection) + : mMirConnection(mirConnection) +{ + mir_connection_set_display_config_change_callback(mirConnection, ::displayConfigurationChangedCallback, this); + update(); +} + +void QMirClientScreenObserver::update() +{ + // Wrap MirDisplayConfiguration to always delete when out of scope + auto configDeleter = [](MirDisplayConfig *config) { mir_display_config_release(config); }; + using configUp = std::unique_ptr<MirDisplayConfig, decltype(configDeleter)>; + configUp displayConfig(mir_connection_create_display_configuration(mMirConnection), configDeleter); + + // Mir only tells us something changed, it is up to us to figure out what. + QList<QMirClientScreen*> newScreenList; + QList<QMirClientScreen*> oldScreenList = mScreenList; + mScreenList.clear(); + + for (int i = 0; i < mir_display_config_get_num_outputs(displayConfig.get()); i++) { + const MirOutput *output = mir_display_config_get_output(displayConfig.get(), i); + if (mir_output_is_enabled(output)) { + QMirClientScreen *screen = findScreenWithId(oldScreenList, mir_output_get_id(output)); + if (screen) { // we've already set up this display before + screen->updateMirOutput(output); + oldScreenList.removeAll(screen); + } else { + // new display, so create QMirClientScreen for it + screen = new QMirClientScreen(output, mMirConnection); + newScreenList.append(screen); + qCDebug(mirclient) << "Added Screen with id" << mir_output_get_id(output) + << "and geometry" << screen->geometry(); + } + mScreenList.append(screen); + } + } + + // Announce old & unused Screens, should be deleted by the slot + Q_FOREACH (const auto screen, oldScreenList) { + Q_EMIT screenRemoved(screen); + } + + /* + * Mir's MirDisplayOutput does not include formFactor or scale for some reason, but Qt + * will want that information on creating the QScreen. Only way we get that info is when + * Mir positions a Window on that Screen. See "handleScreenPropertiesChange" method + */ + + // Announce new Screens + Q_FOREACH (const auto screen, newScreenList) { + Q_EMIT screenAdded(screen); + } + + qCDebug(mirclient) << "======================================="; + for (auto screen: mScreenList) { + qCDebug(mirclient) << screen << "- id:" << screen->mirOutputId() + << "geometry:" << screen->geometry() + << "form factor:" << mirFormFactorToStr(screen->formFactor()) + << "scale:" << screen->scale(); + } + qCDebug(mirclient) << "======================================="; +} + +QMirClientScreen *QMirClientScreenObserver::findScreenWithId(int id) +{ + return findScreenWithId(mScreenList, id); +} + +QMirClientScreen *QMirClientScreenObserver::findScreenWithId(const QList<QMirClientScreen *> &list, int id) +{ + Q_FOREACH (const auto screen, list) { + if (screen->mirOutputId() == id) { + return screen; + } + } + return nullptr; +} + +void QMirClientScreenObserver::handleScreenPropertiesChange(QMirClientScreen *screen, int dpi, + MirFormFactor formFactor, float scale) +{ + screen->setAdditionalMirDisplayProperties(scale, formFactor, dpi); +} + diff --git a/src/plugins/platforms/mirclient/qmirclientscreenobserver.h b/src/plugins/platforms/mirclient/qmirclientscreenobserver.h new file mode 100644 index 0000000000..ad927319c1 --- /dev/null +++ b/src/plugins/platforms/mirclient/qmirclientscreenobserver.h @@ -0,0 +1,78 @@ +/**************************************************************************** +** +** Copyright (C) 2016 Canonical, Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#ifndef QMIRCLIENTSCREENOBSERVER_H +#define QMIRCLIENTSCREENOBSERVER_H + +#include <QObject> + +#include <mir_toolkit/mir_connection.h> + +class QMirClientScreen; + +class QMirClientScreenObserver : public QObject +{ + Q_OBJECT + +public: + QMirClientScreenObserver(MirConnection *connection); + + QList<QMirClientScreen*> screens() const { return mScreenList; } + QMirClientScreen *findScreenWithId(int id); + + void handleScreenPropertiesChange(QMirClientScreen *screen, int dpi, + MirFormFactor formFactor, float scale); + +Q_SIGNALS: + void screenAdded(QMirClientScreen *screen); + void screenRemoved(QMirClientScreen *screen); + +private Q_SLOTS: + void update(); + +private: + QMirClientScreen *findScreenWithId(const QList<QMirClientScreen *> &list, int id); + void removeScreen(QMirClientScreen *screen); + + MirConnection *mMirConnection; + QList<QMirClientScreen*> mScreenList; +}; + +#endif // QMIRCLIENTSCREENOBSERVER_H diff --git a/src/plugins/platforms/mirclient/qmirclientwindow.cpp b/src/plugins/platforms/mirclient/qmirclientwindow.cpp index 60b9cd7900..adc8ae652a 100644 --- a/src/plugins/platforms/mirclient/qmirclientwindow.cpp +++ b/src/plugins/platforms/mirclient/qmirclientwindow.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2014-2015 Canonical, Ltd. +** Copyright (C) 2014-2016 Canonical, Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the plugins of the Qt Toolkit. @@ -40,26 +40,33 @@ // Local #include "qmirclientwindow.h" -#include "qmirclientclipboard.h" +#include "qmirclientdebugextension.h" +#include "qmirclientnativeinterface.h" #include "qmirclientinput.h" +#include "qmirclientintegration.h" #include "qmirclientscreen.h" #include "qmirclientlogging.h" #include <mir_toolkit/mir_client_library.h> +#include <mir_toolkit/version.h> // Qt #include <qpa/qwindowsysteminterface.h> #include <QMutexLocker> #include <QSize> #include <QtMath> +#include <QtEglSupport/private/qeglconvenience_p.h> // Platform API #include <ubuntu/application/instance.h> #include <EGL/egl.h> +Q_LOGGING_CATEGORY(mirclientBufferSwap, "qt.qpa.mirclient.bufferSwap", QtWarningMsg) + namespace { +const Qt::WindowType LowChromeWindowHint = (Qt::WindowType)0x00800000; // FIXME: this used to be defined by platform-api, but it's been removed in v3. Change ubuntu-keyboard to use // a different enum for window roles. @@ -87,40 +94,110 @@ EGLNativeWindowType nativeWindowFor(MirSurface *surf) return reinterpret_cast<EGLNativeWindowType>(mir_buffer_stream_get_egl_native_window(stream)); } -MirSurfaceState qtWindowStateToMirSurfaceState(Qt::WindowState state) +const char *qtWindowStateToStr(Qt::WindowState state) { switch (state) { case Qt::WindowNoState: - return mir_surface_state_restored; + return "NoState"; case Qt::WindowFullScreen: - return mir_surface_state_fullscreen; + return "FullScreen"; case Qt::WindowMaximized: - return mir_surface_state_maximized; + return "Maximized"; case Qt::WindowMinimized: - return mir_surface_state_minimized; - default: - LOG("Unexpected Qt::WindowState: %d", state); - return mir_surface_state_restored; + return "Minimized"; + case Qt::WindowActive: + return "Active"; } + Q_UNREACHABLE(); } -#if !defined(QT_NO_DEBUG) -const char *qtWindowStateToStr(Qt::WindowState state) +const char *mirSurfaceStateToStr(MirSurfaceState surfaceState) +{ + switch (surfaceState) { + case mir_surface_state_unknown: return "unknown"; + case mir_surface_state_restored: return "restored"; + case mir_surface_state_minimized: return "minimized"; + case mir_surface_state_maximized: return "vertmaximized"; + case mir_surface_state_vertmaximized: return "vertmaximized"; + case mir_surface_state_fullscreen: return "fullscreen"; + case mir_surface_state_horizmaximized: return "horizmaximized"; + case mir_surface_state_hidden: return "hidden"; + case mir_surface_states: Q_UNREACHABLE(); + } + Q_UNREACHABLE(); +} + +const char *mirPixelFormatToStr(MirPixelFormat pixelFormat) +{ + switch (pixelFormat) { + case mir_pixel_format_invalid: return "invalid"; + case mir_pixel_format_abgr_8888: return "ABGR8888"; + case mir_pixel_format_xbgr_8888: return "XBGR8888"; + case mir_pixel_format_argb_8888: return "ARGB8888"; + case mir_pixel_format_xrgb_8888: return "XRGB8888"; + case mir_pixel_format_bgr_888: return "BGR888"; + case mir_pixel_format_rgb_888: return "RGB888"; + case mir_pixel_format_rgb_565: return "RGB565"; + case mir_pixel_format_rgba_5551: return "RGBA5551"; + case mir_pixel_format_rgba_4444: return "RGBA4444"; + case mir_pixel_formats: Q_UNREACHABLE(); + } + Q_UNREACHABLE(); +} + +const char *mirSurfaceTypeToStr(MirSurfaceType type) +{ + switch (type) { + case mir_surface_type_normal: return "Normal"; /**< AKA "regular" */ + case mir_surface_type_utility: return "Utility"; /**< AKA "floating regular" */ + case mir_surface_type_dialog: return "Dialog"; + case mir_surface_type_gloss: return "Gloss"; + case mir_surface_type_freestyle: return "Freestyle"; + case mir_surface_type_menu: return "Menu"; + case mir_surface_type_inputmethod: return "Input Method"; /**< AKA "OSK" or handwriting etc. */ + case mir_surface_type_satellite: return "Satellite"; /**< AKA "toolbox"/"toolbar" */ + case mir_surface_type_tip: return "Tip"; /**< AKA "tooltip" */ + case mir_surface_types: Q_UNREACHABLE(); + } + return ""; +} + +MirSurfaceState qtWindowStateToMirSurfaceState(Qt::WindowState state) { switch (state) { case Qt::WindowNoState: - return "NoState"; + case Qt::WindowActive: + return mir_surface_state_restored; case Qt::WindowFullScreen: - return "FullScreen"; + return mir_surface_state_fullscreen; case Qt::WindowMaximized: - return "Maximized"; + return mir_surface_state_maximized; case Qt::WindowMinimized: - return "Minimized"; + return mir_surface_state_minimized; + } + return mir_surface_state_unknown; // should never be reached +} + +MirSurfaceType qtWindowTypeToMirSurfaceType(Qt::WindowType type) +{ + switch (type & Qt::WindowType_Mask) { + case Qt::Dialog: + return mir_surface_type_dialog; + case Qt::Sheet: + case Qt::Drawer: + return mir_surface_type_utility; + case Qt::Popup: + case Qt::Tool: + return mir_surface_type_menu; + case Qt::ToolTip: + return mir_surface_type_tip; + case Qt::SplashScreen: + return mir_surface_type_freestyle; + case Qt::Window: default: - return "!?"; + return mir_surface_type_normal; } } -#endif WId makeId() { @@ -128,14 +205,6 @@ WId makeId() return id++; } -MirPixelFormat defaultPixelFormatFor(MirConnection *connection) -{ - MirPixelFormat format; - unsigned int nformats; - mir_connection_get_available_surface_formats(connection, &format, 1, &nformats); - return format; -} - UAUiWindowRole roleFor(QWindow *window) { QVariant roleVariant = window->property("role"); @@ -155,52 +224,93 @@ QMirClientWindow *transientParentFor(QWindow *window) return parent ? static_cast<QMirClientWindow *>(parent->handle()) : nullptr; } -Spec makeSurfaceSpec(QWindow *window, QMirClientInput *input, MirConnection *connection) -{ - const auto geom = window->geometry(); - const int width = geom.width() > 0 ? geom.width() : 1; - const int height = geom.height() > 0 ? geom.height() : 1; - const auto pixelFormat = defaultPixelFormatFor(connection); - - if (U_ON_SCREEN_KEYBOARD_ROLE == roleFor(window)) { - DLOG("[ubuntumirclient QPA] makeSurfaceSpec(window=%p) - creating input method surface (width=%d, height=%d", window, width, height); - return Spec{mir_connection_create_spec_for_input_method(connection, width, height, pixelFormat)}; - } - - const Qt::WindowType type = window->type(); - if (type == Qt::Popup) { - auto parent = transientParentFor(window); - if (parent == nullptr) { - //NOTE: We cannot have a parentless popup - - //try using the last surface to receive input as that will most likely be - //the one that caused this popup to be created - parent = input->lastFocusedWindow(); - } - if (parent) { - auto pos = geom.topLeft(); - pos -= parent->geometry().topLeft(); - MirRectangle location{pos.x(), pos.y(), 0, 0}; - DLOG("[ubuntumirclient QPA] makeSurfaceSpec(window=%p) - creating menu surface(width:%d, height:%d)", window, width, height); - return Spec{mir_connection_create_spec_for_menu( - connection, width, height, pixelFormat, parent->mirSurface(), - &location, mir_edge_attachment_any)}; - } else { - DLOG("[ubuntumirclient QPA] makeSurfaceSpec(window=%p) - cannot create a menu without a parent!", window); - } - } else if (type == Qt::Dialog) { - auto parent = transientParentFor(window); - if (parent) { - // Modal dialog - DLOG("[ubuntumirclient QPA] makeSurfaceSpec(window=%p) - creating modal dialog (width=%d, height=%d", window, width, height); - return Spec{mir_connection_create_spec_for_modal_dialog(connection, width, height, pixelFormat, parent->mirSurface())}; - } else { - // TODO: do Qt parentless dialogs have the same semantics as mir? - DLOG("[ubuntumirclient QPA] makeSurfaceSpec(window=%p) - creating parentless dialog (width=%d, height=%d)", window, width, height); - return Spec{mir_connection_create_spec_for_dialog(connection, width, height, pixelFormat)}; - } - } - DLOG("[ubuntumirclient QPA] makeSurfaceSpec(window=%p) - creating normal surface(type=0x%x, width=%d, height=%d)", window, type, width, height); - return Spec{mir_connection_create_spec_for_normal_surface(connection, width, height, pixelFormat)}; +bool requiresParent(const MirSurfaceType type) +{ + switch (type) { + case mir_surface_type_dialog: //FIXME - not quite what the specification dictates, but is what Mir's api dictates + case mir_surface_type_utility: + case mir_surface_type_gloss: + case mir_surface_type_menu: + case mir_surface_type_satellite: + case mir_surface_type_tip: + return true; + default: + return false; + } +} + +bool requiresParent(const Qt::WindowType type) +{ + return requiresParent(qtWindowTypeToMirSurfaceType(type)); +} + +bool isMovable(const Qt::WindowType type) +{ + auto mirType = qtWindowTypeToMirSurfaceType(type); + switch (mirType) { + case mir_surface_type_menu: + case mir_surface_type_tip: + return true; + default: + return false; + } +} + +Spec makeSurfaceSpec(QWindow *window, MirPixelFormat pixelFormat, QMirClientWindow *parentWindowHandle, + MirConnection *connection) +{ + const auto geometry = window->geometry(); + const int width = geometry.width() > 0 ? geometry.width() : 1; + const int height = geometry.height() > 0 ? geometry.height() : 1; + auto type = qtWindowTypeToMirSurfaceType(window->type()); + + if (U_ON_SCREEN_KEYBOARD_ROLE == roleFor(window)) { + type = mir_surface_type_inputmethod; + } + + MirRectangle location{geometry.x(), geometry.y(), 0, 0}; + MirSurface *parent = nullptr; + if (parentWindowHandle) { + parent = parentWindowHandle->mirSurface(); + // Qt uses absolute positioning, but Mir positions surfaces relative to parent. + location.top -= parentWindowHandle->geometry().top(); + location.left -= parentWindowHandle->geometry().left(); + } + + Spec spec; + + switch (type) { + case mir_surface_type_menu: + spec = Spec{mir_connection_create_spec_for_menu(connection, width, height, pixelFormat, parent, + &location, mir_edge_attachment_any)}; + break; + case mir_surface_type_dialog: + spec = Spec{mir_connection_create_spec_for_modal_dialog(connection, width, height, pixelFormat, parent)}; + break; + case mir_surface_type_utility: + spec = Spec{mir_connection_create_spec_for_dialog(connection, width, height, pixelFormat)}; + break; + case mir_surface_type_tip: +#if MIR_CLIENT_VERSION < MIR_VERSION_NUMBER(3, 4, 0) + spec = Spec{mir_connection_create_spec_for_tooltip(connection, width, height, pixelFormat, parent, + &location)}; +#else + spec = Spec{mir_connection_create_spec_for_tip(connection, width, height, pixelFormat, parent, + &location, mir_edge_attachment_any)}; +#endif + break; + case mir_surface_type_inputmethod: + spec = Spec{mir_connection_create_spec_for_input_method(connection, width, height, pixelFormat)}; + break; + default: + spec = Spec{mir_connection_create_spec_for_normal_surface(connection, width, height, pixelFormat)}; + break; + } + + qCDebug(mirclient, "makeSurfaceSpec(window=%p): %s spec (type=0x%x, position=(%d, %d)px, size=(%dx%d)px)", + window, mirSurfaceTypeToStr(type), window->type(), location.left, location.top, width, height); + + return std::move(spec); } void setSizingConstraints(MirSurfaceSpec *spec, const QSize& minSize, const QSize& maxSize, const QSize& increment) @@ -221,16 +331,30 @@ void setSizingConstraints(MirSurfaceSpec *spec, const QSize& minSize, const QSiz } } -MirSurface *createMirSurface(QWindow *window, QMirClientScreen *screen, QMirClientInput *input, MirConnection *connection) +MirSurface *createMirSurface(QWindow *window, int mirOutputId, QMirClientWindow *parentWindowHandle, + MirPixelFormat pixelFormat, MirConnection *connection, + mir_surface_event_callback inputCallback, void *inputContext) { - auto spec = makeSurfaceSpec(window, input, connection); + auto spec = makeSurfaceSpec(window, pixelFormat, parentWindowHandle, connection); + + // Install event handler as early as possible + mir_surface_spec_set_event_handler(spec.get(), inputCallback, inputContext); + const auto title = window->title().toUtf8(); mir_surface_spec_set_name(spec.get(), title.constData()); setSizingConstraints(spec.get(), window->minimumSize(), window->maximumSize(), window->sizeIncrement()); if (window->windowState() == Qt::WindowFullScreen) { - mir_surface_spec_set_fullscreen_on_output(spec.get(), screen->mirOutputId()); + mir_surface_spec_set_fullscreen_on_output(spec.get(), mirOutputId); + } + + if (window->flags() & LowChromeWindowHint) { + mir_surface_spec_set_shell_chrome(spec.get(), mir_shell_chrome_low); + } + + if (!window->isVisible()) { + mir_surface_spec_set_state(spec.get(), mir_surface_state_hidden); } auto surface = mir_surface_create_sync(spec.get()); @@ -238,83 +362,45 @@ MirSurface *createMirSurface(QWindow *window, QMirClientScreen *screen, QMirClie return surface; } -// FIXME - in order to work around https://bugs.launchpad.net/mir/+bug/1346633 -// we need to guess the panel height (3GU) -int panelHeight() -{ - if (qEnvironmentVariableIsSet("QT_MIRCLIENT_IGNORE_PANEL")) - return 0; - const int defaultGridUnit = 8; - int gridUnit = defaultGridUnit; - QByteArray gridUnitString = qgetenv("GRID_UNIT_PX"); - if (!gridUnitString.isEmpty()) { - bool ok; - gridUnit = gridUnitString.toInt(&ok); - if (!ok) { - gridUnit = defaultGridUnit; +QMirClientWindow *getParentIfNecessary(QWindow *window, QMirClientInput *input) +{ + QMirClientWindow *parentWindowHandle = nullptr; + if (requiresParent(window->type())) { + parentWindowHandle = transientParentFor(window); + if (parentWindowHandle == nullptr) { + // NOTE: Mir requires this surface have a parent. Try using the last surface to receive input as that will + // most likely be the one that caused this surface to be created + parentWindowHandle = input->lastInputWindow(); } } - return gridUnit * 3; + return parentWindowHandle; } -} //namespace - -class QMirClientSurface +MirPixelFormat disableAlphaBufferIfPossible(MirPixelFormat pixelFormat) { -public: - QMirClientSurface(QMirClientWindow *platformWindow, QMirClientScreen *screen, QMirClientInput *input, MirConnection *connection) - : mWindow(platformWindow->window()) - , mPlatformWindow(platformWindow) - , mInput(input) - , mConnection(connection) - , mMirSurface(createMirSurface(mWindow, screen, input, connection)) - , mEglDisplay(screen->eglDisplay()) - , mEglSurface(eglCreateWindowSurface(mEglDisplay, screen->eglConfig(), nativeWindowFor(mMirSurface), nullptr)) - , mVisible(false) - , mNeedsRepaint(false) - , mParented(mWindow->transientParent() || mWindow->parent()) - , mWindowState(mWindow->windowState()) - - { - mir_surface_set_event_handler(mMirSurface, surfaceEventCallback, this); - - // Window manager can give us a final size different from what we asked for - // so let's check what we ended up getting - MirSurfaceParameters parameters; - mir_surface_get_parameters(mMirSurface, ¶meters); - - auto geom = mWindow->geometry(); - geom.setWidth(parameters.width); - geom.setHeight(parameters.height); - if (mWindowState == Qt::WindowFullScreen) { - geom.setY(0); - } else { - geom.setY(panelHeight()); - } + switch (pixelFormat) { + case mir_pixel_format_abgr_8888: + return mir_pixel_format_xbgr_8888; + case mir_pixel_format_argb_8888: + return mir_pixel_format_xrgb_8888; + default: // can do nothing, leave it alone + return pixelFormat; + } +} +} //namespace - // Assume that the buffer size matches the surface size at creation time - mBufferSize = geom.size(); - platformWindow->QPlatformWindow::setGeometry(geom); - QWindowSystemInterface::handleGeometryChange(mWindow, geom); - DLOG("[ubuntumirclient QPA] created surface at (%d, %d) with size (%d, %d), title '%s', role: '%d'\n", - geom.x(), geom.y(), geom.width(), geom.height(), mWindow->title().toUtf8().constData(), roleFor(mWindow)); - } - ~QMirClientSurface() - { - if (mEglSurface != EGL_NO_SURFACE) - eglDestroySurface(mEglDisplay, mEglSurface); - if (mMirSurface) - mir_surface_release_sync(mMirSurface); - } +class UbuntuSurface +{ +public: + UbuntuSurface(QMirClientWindow *platformWindow, EGLDisplay display, QMirClientInput *input, MirConnection *connection); + ~UbuntuSurface(); - QMirClientSurface(QMirClientSurface const&) = delete; - QMirClientSurface& operator=(QMirClientSurface const&) = delete; + UbuntuSurface(const UbuntuSurface &) = delete; + UbuntuSurface& operator=(const UbuntuSurface &) = delete; - void resize(const QSize& newSize); - void setState(Qt::WindowState newState); - void setVisible(bool state); + void updateGeometry(const QRect &newGeometry); void updateTitle(const QString& title); void setSizingConstraints(const QSize& minSize, const QSize& maxSize, const QSize& increment); @@ -322,76 +408,151 @@ public: void handleSurfaceResized(int width, int height); int needsRepaint() const; + MirSurfaceState state() const { return mir_surface_get_state(mMirSurface); } + void setState(MirSurfaceState state); + + MirSurfaceType type() const { return mir_surface_get_type(mMirSurface); } + + void setShellChrome(MirShellChrome shellChrome); + EGLSurface eglSurface() const { return mEglSurface; } MirSurface *mirSurface() const { return mMirSurface; } + void setSurfaceParent(MirSurface*); + bool hasParent() const { return mParented; } + + QSurfaceFormat format() const { return mFormat; } + + bool mNeedsExposeCatchup; + + QString persistentSurfaceId(); + private: static void surfaceEventCallback(MirSurface* surface, const MirEvent *event, void* context); void postEvent(const MirEvent *event); - void updateSurface(); QWindow * const mWindow; QMirClientWindow * const mPlatformWindow; QMirClientInput * const mInput; MirConnection * const mConnection; + QMirClientWindow * mParentWindowHandle{nullptr}; - MirSurface * const mMirSurface; + MirSurface* mMirSurface; const EGLDisplay mEglDisplay; - const EGLSurface mEglSurface; + EGLSurface mEglSurface; - bool mVisible; bool mNeedsRepaint; bool mParented; - Qt::WindowState mWindowState; QSize mBufferSize; + QSurfaceFormat mFormat; + MirPixelFormat mPixelFormat; QMutex mTargetSizeMutex; QSize mTargetSize; + MirShellChrome mShellChrome; + QString mPersistentIdStr; }; -void QMirClientSurface::resize(const QSize& size) -{ - DLOG("[ubuntumirclient QPA] resize(window=%p, width=%d, height=%d)", mWindow, size.width(), size.height()); - - if (mWindowState == Qt::WindowFullScreen || mWindowState == Qt::WindowMaximized) { - DLOG("[ubuntumirclient QPA] resize(window=%p) - not resizing, window is maximized or fullscreen", mWindow); - return; +UbuntuSurface::UbuntuSurface(QMirClientWindow *platformWindow, EGLDisplay display, QMirClientInput *input, MirConnection *connection) + : mWindow(platformWindow->window()) + , mPlatformWindow(platformWindow) + , mInput(input) + , mConnection(connection) + , mEglDisplay(display) + , mNeedsRepaint(false) + , mParented(mWindow->transientParent() || mWindow->parent()) + , mFormat(mWindow->requestedFormat()) + , mShellChrome(mWindow->flags() & LowChromeWindowHint ? mir_shell_chrome_low : mir_shell_chrome_normal) +{ + // Have Qt choose most suitable EGLConfig for the requested surface format, and update format to reflect it + EGLConfig config = q_configFromGLFormat(display, mFormat, true); + if (config == 0) { + // Older Intel Atom-based devices only support OpenGL 1.4 compatibility profile but by default + // QML asks for at least OpenGL 2.0. The XCB GLX backend ignores this request and returns a + // 1.4 context, but the XCB EGL backend tries to honor it, and fails. The 1.4 context appears to + // have sufficient capabilities on MESA (i915) to render correctly however. So reduce the default + // requested OpenGL version to 1.0 to ensure EGL will give us a working context (lp:1549455). + static const bool isMesa = QString(eglQueryString(display, EGL_VENDOR)).contains(QStringLiteral("Mesa")); + if (isMesa) { + qCDebug(mirclientGraphics, "Attempting to choose OpenGL 1.4 context which may suit Mesa"); + mFormat.setMajorVersion(1); + mFormat.setMinorVersion(4); + config = q_configFromGLFormat(display, mFormat, true); + } + } + if (config == 0) { + qCritical() << "Qt failed to choose a suitable EGLConfig to suit the surface format" << mFormat; } - if (size.isEmpty()) { - DLOG("[ubuntumirclient QPA] resize(window=%p) - not resizing, size is empty", mWindow); - return; + mFormat = q_glFormatFromConfig(display, config, mFormat); + + // Have Mir decide the pixel format most suited to the chosen EGLConfig. This is the only way + // Mir will know what EGLConfig has been chosen - it cannot deduce it from the buffers. + mPixelFormat = mir_connection_get_egl_pixel_format(connection, display, config); + // But the chosen EGLConfig might have an alpha buffer enabled, even if not requested by the client. + // If that's the case, try to edit the chosen pixel format in order to disable the alpha buffer. + // This is an optimization for the compositor, as it can avoid blending this surface. + if (mWindow->requestedFormat().alphaBufferSize() < 0) { + mPixelFormat = disableAlphaBufferIfPossible(mPixelFormat); } - Spec spec{mir_connection_create_spec_for_changes(mConnection)}; - mir_surface_spec_set_width(spec.get(), size.width()); - mir_surface_spec_set_height(spec.get(), size.height()); - mir_surface_apply_spec(mMirSurface, spec.get()); + const auto outputId = static_cast<QMirClientScreen *>(mWindow->screen()->handle())->mirOutputId(); + + mParentWindowHandle = getParentIfNecessary(mWindow, input); + + mMirSurface = createMirSurface(mWindow, outputId, mParentWindowHandle, mPixelFormat, connection, surfaceEventCallback, this); + mEglSurface = eglCreateWindowSurface(mEglDisplay, config, nativeWindowFor(mMirSurface), nullptr); + + mNeedsExposeCatchup = mir_surface_get_visibility(mMirSurface) == mir_surface_visibility_occluded; + + // Window manager can give us a final size different from what we asked for + // so let's check what we ended up getting + MirSurfaceParameters parameters; + mir_surface_get_parameters(mMirSurface, ¶meters); + + auto geom = mWindow->geometry(); + geom.setWidth(parameters.width); + geom.setHeight(parameters.height); + + // Assume that the buffer size matches the surface size at creation time + mBufferSize = geom.size(); + platformWindow->QPlatformWindow::setGeometry(geom); + QWindowSystemInterface::handleGeometryChange(mWindow, geom); + + qCDebug(mirclient) << "Created surface with geometry:" << geom << "title:" << mWindow->title() + << "role:" << roleFor(mWindow); + qCDebug(mirclientGraphics) + << "Requested format:" << mWindow->requestedFormat() + << "\nActual format:" << mFormat + << "with associated Mir pixel format:" << mirPixelFormatToStr(mPixelFormat); } -void QMirClientSurface::setState(Qt::WindowState newState) +UbuntuSurface::~UbuntuSurface() { - mir_wait_for(mir_surface_set_state(mMirSurface, qtWindowStateToMirSurfaceState(newState))); - mWindowState = newState; + if (mEglSurface != EGL_NO_SURFACE) + eglDestroySurface(mEglDisplay, mEglSurface); + if (mMirSurface) { + mir_surface_release_sync(mMirSurface); + } } -void QMirClientSurface::setVisible(bool visible) +void UbuntuSurface::updateGeometry(const QRect &newGeometry) { - if (mVisible == visible) - return; - - mVisible = visible; + qCDebug(mirclient,"updateGeometry(window=%p, width=%d, height=%d)", mWindow, + newGeometry.width(), newGeometry.height()); - if (mVisible) - updateSurface(); - - // TODO: Use the new mir_surface_state_hidden state instead of mir_surface_state_minimized. - // Will have to change qtmir and unity8 for that. - const auto newState = visible ? qtWindowStateToMirSurfaceState(mWindowState) : mir_surface_state_minimized; - mir_wait_for(mir_surface_set_state(mMirSurface, newState)); + Spec spec; + if (isMovable(mWindow->type())) { + spec = Spec{makeSurfaceSpec(mWindow, mPixelFormat, mParentWindowHandle, mConnection)}; + } else { + spec = Spec{mir_connection_create_spec_for_changes(mConnection)}; + mir_surface_spec_set_width(spec.get(), newGeometry.width()); + mir_surface_spec_set_height(spec.get(), newGeometry.height()); + } + mir_surface_apply_spec(mMirSurface, spec.get()); } -void QMirClientSurface::updateTitle(const QString& newTitle) +void UbuntuSurface::updateTitle(const QString& newTitle) { const auto title = newTitle.toUtf8(); Spec spec{mir_connection_create_spec_for_changes(mConnection)}; @@ -399,14 +560,14 @@ void QMirClientSurface::updateTitle(const QString& newTitle) mir_surface_apply_spec(mMirSurface, spec.get()); } -void QMirClientSurface::setSizingConstraints(const QSize& minSize, const QSize& maxSize, const QSize& increment) +void UbuntuSurface::setSizingConstraints(const QSize& minSize, const QSize& maxSize, const QSize& increment) { Spec spec{mir_connection_create_spec_for_changes(mConnection)}; ::setSizingConstraints(spec.get(), minSize, maxSize, increment); mir_surface_apply_spec(mMirSurface, spec.get()); } -void QMirClientSurface::handleSurfaceResized(int width, int height) +void UbuntuSurface::handleSurfaceResized(int width, int height) { QMutexLocker lock(&mTargetSizeMutex); @@ -419,7 +580,7 @@ void QMirClientSurface::handleSurfaceResized(int width, int height) mNeedsRepaint = mTargetSize.width() == width && mTargetSize.height() == height; } -int QMirClientSurface::needsRepaint() const +int UbuntuSurface::needsRepaint() const { if (mNeedsRepaint) { if (mTargetSize != mBufferSize) { @@ -436,12 +597,26 @@ int QMirClientSurface::needsRepaint() const return 0; } -void QMirClientSurface::onSwapBuffersDone() +void UbuntuSurface::setState(MirSurfaceState state) +{ + mir_wait_for(mir_surface_set_state(mMirSurface, state)); +} + +void UbuntuSurface::setShellChrome(MirShellChrome chrome) +{ + if (chrome != mShellChrome) { + auto spec = Spec{mir_connection_create_spec_for_changes(mConnection)}; + mir_surface_spec_set_shell_chrome(spec.get(), chrome); + mir_surface_apply_spec(mMirSurface, spec.get()); + + mShellChrome = chrome; + } +} + +void UbuntuSurface::onSwapBuffersDone() { -#if !defined(QT_NO_DEBUG) static int sFrameNumber = 0; ++sFrameNumber; -#endif EGLint eglSurfaceWidth = -1; EGLint eglSurfaceHeight = -1; @@ -452,7 +627,7 @@ void QMirClientSurface::onSwapBuffersDone() if (validSize && (mBufferSize.width() != eglSurfaceWidth || mBufferSize.height() != eglSurfaceHeight)) { - DLOG("[ubuntumirclient QPA] onSwapBuffersDone(window=%p) [%d] - size changed (%d, %d) => (%d, %d)", + qCDebug(mirclientBufferSwap, "onSwapBuffersDone(window=%p) [%d] - size changed (%d, %d) => (%d, %d)", mWindow, sFrameNumber, mBufferSize.width(), mBufferSize.height(), eglSurfaceWidth, eglSurfaceHeight); mBufferSize.rwidth() = eglSurfaceWidth; @@ -464,23 +639,21 @@ void QMirClientSurface::onSwapBuffersDone() mPlatformWindow->QPlatformWindow::setGeometry(newGeometry); QWindowSystemInterface::handleGeometryChange(mWindow, newGeometry); } else { -#if 0 - DLOG("[ubuntumirclient QPA] onSwapBuffersDone(window=%p) [%d] - buffer size (%d,%d)", + qCDebug(mirclientBufferSwap, "onSwapBuffersDone(window=%p) [%d] - buffer size (%d,%d)", mWindow, sFrameNumber, mBufferSize.width(), mBufferSize.height()); -#endif } } -void QMirClientSurface::surfaceEventCallback(MirSurface *surface, const MirEvent *event, void* context) +void UbuntuSurface::surfaceEventCallback(MirSurface *surface, const MirEvent *event, void* context) { Q_UNUSED(surface); Q_ASSERT(context != nullptr); - auto s = static_cast<QMirClientSurface *>(context); + auto s = static_cast<UbuntuSurface *>(context); s->postEvent(event); } -void QMirClientSurface::postEvent(const MirEvent *event) +void UbuntuSurface::postEvent(const MirEvent *event) { if (mir_event_type_resize == mir_event_get_type(event)) { // TODO: The current event queue just accumulates all resize events; @@ -490,7 +663,7 @@ void QMirClientSurface::postEvent(const MirEvent *event) const auto resizeEvent = mir_event_get_resize_event(event); const auto width = mir_resize_event_get_width(resizeEvent); const auto height = mir_resize_event_get_height(resizeEvent); - DLOG("[ubuntumirclient QPA] resizeEvent(window=%p, width=%d, height=%d)", mWindow, width, height); + qCDebug(mirclient, "resizeEvent(window=%p, width=%d, height=%d)", mWindow, width, height); QMutexLocker lock(&mTargetSizeMutex); mTargetSize.rwidth() = width; @@ -500,44 +673,57 @@ void QMirClientSurface::postEvent(const MirEvent *event) mInput->postEvent(mPlatformWindow, event); } -void QMirClientSurface::updateSurface() +void UbuntuSurface::setSurfaceParent(MirSurface* parent) { - DLOG("[ubuntumirclient QPA] updateSurface(window=%p)", mWindow); + qCDebug(mirclient, "setSurfaceParent(window=%p)", mWindow); - if (!mParented && mWindow->type() == Qt::Dialog) { - // The dialog may have been parented after creation time - // so morph it into a modal dialog - auto parent = transientParentFor(mWindow); - if (parent) { - DLOG("[ubuntumirclient QPA] updateSurface(window=%p) dialog now parented", mWindow); - mParented = true; - Spec spec{mir_connection_create_spec_for_changes(mConnection)}; - mir_surface_spec_set_parent(spec.get(), parent->mirSurface()); - mir_surface_apply_spec(mMirSurface, spec.get()); - } + mParented = true; + Spec spec{mir_connection_create_spec_for_changes(mConnection)}; + mir_surface_spec_set_parent(spec.get(), parent); + mir_surface_apply_spec(mMirSurface, spec.get()); +} + +QString UbuntuSurface::persistentSurfaceId() +{ + if (mPersistentIdStr.isEmpty()) { + MirPersistentId* mirPermaId = mir_surface_request_persistent_id_sync(mMirSurface); + mPersistentIdStr = mir_persistent_id_as_string(mirPermaId); + mir_persistent_id_release(mirPermaId); } + return mPersistentIdStr; } -QMirClientWindow::QMirClientWindow(QWindow *w, const QSharedPointer<QMirClientClipboard> &clipboard, QMirClientScreen *screen, - QMirClientInput *input, MirConnection *connection) +QMirClientWindow::QMirClientWindow(QWindow *w, QMirClientInput *input, QMirClientNativeInterface *native, + QMirClientAppStateController *appState, EGLDisplay eglDisplay, + MirConnection *mirConnection, QMirClientDebugExtension *debugExt) : QObject(nullptr) , QPlatformWindow(w) , mId(makeId()) - , mClipboard(clipboard) - , mSurface(new QMirClientSurface{this, screen, input, connection}) + , mWindowState(w->windowState()) + , mWindowFlags(w->flags()) + , mWindowVisible(false) + , mAppStateController(appState) + , mDebugExtention(debugExt) + , mNativeInterface(native) + , mSurface(new UbuntuSurface{this, eglDisplay, input, mirConnection}) + , mScale(1.0) + , mFormFactor(mir_form_factor_unknown) { - DLOG("[ubuntumirclient QPA] QMirClientWindow(window=%p, screen=%p, input=%p, surf=%p)", w, screen, input, mSurface.get()); + mWindowExposed = mSurface->mNeedsExposeCatchup == false; + + qCDebug(mirclient, "QMirClientWindow(window=%p, screen=%p, input=%p, surf=%p) with title '%s', role: '%d'", + w, w->screen()->handle(), input, mSurface.get(), qPrintable(window()->title()), roleFor(window())); } QMirClientWindow::~QMirClientWindow() { - DLOG("[ubuntumirclient QPA] ~QMirClientWindow(window=%p)", this); + qCDebug(mirclient, "~QMirClientWindow(window=%p)", this); } void QMirClientWindow::handleSurfaceResized(int width, int height) { QMutexLocker lock(&mMutex); - DLOG("[ubuntumirclient QPA] handleSurfaceResize(window=%p, width=%d, height=%d)", window(), width, height); + qCDebug(mirclient, "handleSurfaceResize(window=%p, size=(%dx%d)px", window(), width, height); mSurface->handleSurfaceResized(width, height); @@ -547,88 +733,140 @@ void QMirClientWindow::handleSurfaceResized(int width, int height) // updated size but it still needs re-rendering so another redraw may be needed. // A mir API to drop the currently held buffer would help here, so that we wouldn't have to redraw twice auto const numRepaints = mSurface->needsRepaint(); - DLOG("[ubuntumirclient QPA] handleSurfaceResize(window=%p) redraw %d times", window(), numRepaints); + lock.unlock(); + qCDebug(mirclient, "handleSurfaceResize(window=%p) redraw %d times", window(), numRepaints); for (int i = 0; i < numRepaints; i++) { - DLOG("[ubuntumirclient QPA] handleSurfaceResize(window=%p) repainting width=%d, height=%d", window(), geometry().size().width(), geometry().size().height()); + qCDebug(mirclient, "handleSurfaceResize(window=%p) repainting size=(%dx%d)dp", window(), geometry().size().width(), geometry().size().height()); QWindowSystemInterface::handleExposeEvent(window(), QRect(QPoint(), geometry().size())); } } -void QMirClientWindow::handleSurfaceFocused() +void QMirClientWindow::handleSurfaceExposeChange(bool exposed) { - DLOG("[ubuntumirclient QPA] handleSurfaceFocused(window=%p)", window()); + QMutexLocker lock(&mMutex); + qCDebug(mirclient, "handleSurfaceExposeChange(window=%p, exposed=%s)", window(), exposed ? "true" : "false"); + + mSurface->mNeedsExposeCatchup = false; + if (mWindowExposed == exposed) return; + mWindowExposed = exposed; - // System clipboard contents might have changed while this window was unfocused and without - // this process getting notified about it because it might have been suspended (due to - // application lifecycle policies), thus unable to listen to any changes notified through - // D-Bus. - // Therefore let's ensure we are up to date with the system clipboard now that we are getting - // focused again. - mClipboard->requestDBusClipboardContents(); + lock.unlock(); + QWindowSystemInterface::handleExposeEvent(window(), QRect(QPoint(), geometry().size())); +} + +void QMirClientWindow::handleSurfaceFocusChanged(bool focused) +{ + qCDebug(mirclient, "handleSurfaceFocusChanged(window=%p, focused=%d)", window(), focused); + if (focused) { + mAppStateController->setWindowFocused(true); + QWindowSystemInterface::handleWindowActivated(window(), Qt::ActiveWindowFocusReason); + } else { + mAppStateController->setWindowFocused(false); + } +} + +void QMirClientWindow::handleSurfaceVisibilityChanged(bool visible) +{ + qCDebug(mirclient, "handleSurfaceVisibilityChanged(window=%p, visible=%d)", window(), visible); + + if (mWindowVisible == visible) return; + mWindowVisible = visible; + + QWindowSystemInterface::handleExposeEvent(window(), QRect(QPoint(), geometry().size())); +} + +void QMirClientWindow::handleSurfaceStateChanged(Qt::WindowState state) +{ + qCDebug(mirclient, "handleSurfaceStateChanged(window=%p, %s)", window(), qtWindowStateToStr(state)); + + if (mWindowState == state) return; + mWindowState = state; + + QWindowSystemInterface::handleWindowStateChanged(window(), state); } void QMirClientWindow::setWindowState(Qt::WindowState state) { QMutexLocker lock(&mMutex); - DLOG("[ubuntumirclient QPA] setWindowState(window=%p, %s)", this, qtWindowStateToStr(state)); - mSurface->setState(state); + qCDebug(mirclient, "setWindowState(window=%p, %s)", this, qtWindowStateToStr(state)); + + if (mWindowState == state) return; + mWindowState = state; + + lock.unlock(); + updateSurfaceState(); +} + +void QMirClientWindow::setWindowFlags(Qt::WindowFlags flags) +{ + QMutexLocker lock(&mMutex); + qCDebug(mirclient, "setWindowFlags(window=%p, 0x%x)", this, (int)flags); - updatePanelHeightHack(state); + if (mWindowFlags == flags) return; + mWindowFlags = flags; + + mSurface->setShellChrome(mWindowFlags & LowChromeWindowHint ? mir_shell_chrome_low : mir_shell_chrome_normal); } -/* - FIXME: Mir does not let clients know the position of their windows in the virtual - desktop space. So we have this ugly hack that assumes a phone situation where the - window is always on the top-left corner, right below the indicators panel if not - in fullscreen. - */ -void QMirClientWindow::updatePanelHeightHack(Qt::WindowState state) +QRect QMirClientWindow::geometry() const { - if (state == Qt::WindowFullScreen && geometry().y() != 0) { - QRect newGeometry = geometry(); - newGeometry.setY(0); - QPlatformWindow::setGeometry(newGeometry); - QWindowSystemInterface::handleGeometryChange(window(), newGeometry); - } else if (geometry().y() == 0) { - QRect newGeometry = geometry(); - newGeometry.setY(panelHeight()); - QPlatformWindow::setGeometry(newGeometry); - QWindowSystemInterface::handleGeometryChange(window(), newGeometry); + if (mDebugExtention) { + auto geom = QPlatformWindow::geometry(); + geom.moveTopLeft(mDebugExtention->mapSurfacePointToScreen(mSurface->mirSurface(), QPoint(0,0))); + return geom; + } else { + return QPlatformWindow::geometry(); } } void QMirClientWindow::setGeometry(const QRect& rect) { QMutexLocker lock(&mMutex); - DLOG("[ubuntumirclient QPA] setGeometry (window=%p, x=%d, y=%d, width=%d, height=%d)", - window(), rect.x(), rect.y(), rect.width(), rect.height()); - //NOTE: mir surfaces cannot be moved by the client so ignore the topLeft coordinates - const auto newSize = rect.size(); - auto newGeometry = geometry(); - newGeometry.setSize(newSize); - QPlatformWindow::setGeometry(newGeometry); + if (window()->windowState() == Qt::WindowFullScreen || window()->windowState() == Qt::WindowMaximized) { + qCDebug(mirclient, "setGeometry(window=%p) - not resizing, window is maximized or fullscreen", window()); + return; + } + + qCDebug(mirclient, "setGeometry (window=%p, position=(%d, %d)dp, size=(%dx%d)dp)", + window(), rect.x(), rect.y(), rect.width(), rect.height()); + // Immediately update internal geometry so Qt believes position updated + QRect newPosition(geometry()); + newPosition.moveTo(rect.topLeft()); + QPlatformWindow::setGeometry(newPosition); - mSurface->resize(newSize); + mSurface->updateGeometry(rect); + // Note: don't call handleGeometryChange here, wait to see what Mir replies with. } void QMirClientWindow::setVisible(bool visible) { QMutexLocker lock(&mMutex); - DLOG("[ubuntumirclient QPA] setVisible (window=%p, visible=%s)", window(), visible ? "true" : "false"); - - mSurface->setVisible(visible); - const QRect& exposeRect = visible ? QRect(QPoint(), geometry().size()) : QRect(); + qCDebug(mirclient, "setVisible (window=%p, visible=%s)", window(), visible ? "true" : "false"); + + if (mWindowVisible == visible) return; + mWindowVisible = visible; + + if (visible) { + if (!mSurface->hasParent() && window()->type() == Qt::Dialog) { + // The dialog may have been parented after creation time + // so morph it into a modal dialog + auto parent = transientParentFor(window()); + if (parent) { + mSurface->setSurfaceParent(parent->mirSurface()); + } + } + } lock.unlock(); - QWindowSystemInterface::handleExposeEvent(window(), exposeRect); - QWindowSystemInterface::flushWindowSystemEvents(); + updateSurfaceState(); + QWindowSystemInterface::handleExposeEvent(window(), QRect(QPoint(), geometry().size())); } void QMirClientWindow::setWindowTitle(const QString& title) { QMutexLocker lock(&mMutex); - DLOG("[ubuntumirclient QPA] setWindowTitle(window=%p) title=%s)", window(), title.toUtf8().constData()); + qCDebug(mirclient, "setWindowTitle(window=%p) title=%s)", window(), title.toUtf8().constData()); mSurface->updateTitle(title); } @@ -636,13 +874,33 @@ void QMirClientWindow::propagateSizeHints() { QMutexLocker lock(&mMutex); const auto win = window(); - DLOG("[ubuntumirclient QPA] propagateSizeHints(window=%p) min(%d,%d), max(%d,%d) increment(%d, %d)", - win, win->minimumSize().width(), win->minimumSize().height(), - win->maximumSize().width(), win->maximumSize().height(), - win->sizeIncrement().width(), win->sizeIncrement().height()); + qCDebug(mirclient, "propagateSizeHints(window=%p) min(%d,%d), max(%d,%d) increment(%d, %d)", + win, win->minimumSize().width(), win->minimumSize().height(), + win->maximumSize().width(), win->maximumSize().height(), + win->sizeIncrement().width(), win->sizeIncrement().height()); mSurface->setSizingConstraints(win->minimumSize(), win->maximumSize(), win->sizeIncrement()); } +bool QMirClientWindow::isExposed() const +{ + // mNeedsExposeCatchup because we need to render a frame to get the expose surface event from mir. + return mWindowVisible && (mWindowExposed || (mSurface && mSurface->mNeedsExposeCatchup)); +} + +QSurfaceFormat QMirClientWindow::format() const +{ + return mSurface->format(); +} + +QPoint QMirClientWindow::mapToGlobal(const QPoint &pos) const +{ + if (mDebugExtention) { + return mDebugExtention->mapSurfacePointToScreen(mSurface->mirSurface(), pos); + } else { + return pos; + } +} + void* QMirClientWindow::eglSurface() const { return mSurface->eglSurface(); @@ -662,4 +920,43 @@ void QMirClientWindow::onSwapBuffersDone() { QMutexLocker lock(&mMutex); mSurface->onSwapBuffersDone(); + + if (mSurface->mNeedsExposeCatchup) { + mSurface->mNeedsExposeCatchup = false; + mWindowExposed = false; + + lock.unlock(); + QWindowSystemInterface::handleExposeEvent(window(), QRect(QPoint(), geometry().size())); + } +} + +void QMirClientWindow::handleScreenPropertiesChange(MirFormFactor formFactor, float scale) +{ + // Update the scale & form factor native-interface properties for the windows affected + // as there is no convenient way to emit signals for those custom properties on a QScreen + if (formFactor != mFormFactor) { + mFormFactor = formFactor; + Q_EMIT mNativeInterface->windowPropertyChanged(this, QStringLiteral("formFactor")); + } + + if (!qFuzzyCompare(scale, mScale)) { + mScale = scale; + Q_EMIT mNativeInterface->windowPropertyChanged(this, QStringLiteral("scale")); + } +} + +void QMirClientWindow::updateSurfaceState() +{ + QMutexLocker lock(&mMutex); + MirSurfaceState newState = mWindowVisible ? qtWindowStateToMirSurfaceState(mWindowState) : + mir_surface_state_hidden; + qCDebug(mirclient, "updateSurfaceState (window=%p, surfaceState=%s)", window(), mirSurfaceStateToStr(newState)); + if (newState != mSurface->state()) { + mSurface->setState(newState); + } +} + +QString QMirClientWindow::persistentSurfaceId() +{ + return mSurface->persistentSurfaceId(); } diff --git a/src/plugins/platforms/mirclient/qmirclientwindow.h b/src/plugins/platforms/mirclient/qmirclientwindow.h index 025976c130..324e7691ff 100644 --- a/src/plugins/platforms/mirclient/qmirclientwindow.h +++ b/src/plugins/platforms/mirclient/qmirclientwindow.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2014-2015 Canonical, Ltd. +** Copyright (C) 2014-2016 Canonical, Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the plugins of the Qt Toolkit. @@ -45,44 +45,74 @@ #include <QSharedPointer> #include <QMutex> +#include <mir_toolkit/common.h> // needed only for MirFormFactor enum + #include <memory> -class QMirClientClipboard; +#include <EGL/egl.h> + +class QMirClientAppStateController; +class QMirClientDebugExtension; +class QMirClientNativeInterface; class QMirClientInput; class QMirClientScreen; -class QMirClientSurface; -struct MirConnection; +class UbuntuSurface; struct MirSurface; +class MirConnection; class QMirClientWindow : public QObject, public QPlatformWindow { Q_OBJECT public: - QMirClientWindow(QWindow *w, const QSharedPointer<QMirClientClipboard> &clipboard, QMirClientScreen *screen, - QMirClientInput *input, MirConnection *mirConnection); + QMirClientWindow(QWindow *w, QMirClientInput *input, QMirClientNativeInterface* native, + QMirClientAppStateController *appState, EGLDisplay eglDisplay, + MirConnection *mirConnection, QMirClientDebugExtension *debugExt); virtual ~QMirClientWindow(); // QPlatformWindow methods. WId winId() const override; + QRect geometry() const override; void setGeometry(const QRect&) override; void setWindowState(Qt::WindowState state) override; + void setWindowFlags(Qt::WindowFlags flags) override; void setVisible(bool visible) override; void setWindowTitle(const QString &title) override; void propagateSizeHints() override; + bool isExposed() const override; + + QPoint mapToGlobal(const QPoint &pos) const override; + QSurfaceFormat format() const override; + + // Additional Window properties exposed by NativeInterface + MirFormFactor formFactor() const { return mFormFactor; } + float scale() const { return mScale; } // New methods. void *eglSurface() const; MirSurface *mirSurface() const; void handleSurfaceResized(int width, int height); - void handleSurfaceFocused(); + void handleSurfaceExposeChange(bool exposed); + void handleSurfaceFocusChanged(bool focused); + void handleSurfaceVisibilityChanged(bool visible); + void handleSurfaceStateChanged(Qt::WindowState state); void onSwapBuffersDone(); + void handleScreenPropertiesChange(MirFormFactor formFactor, float scale); + QString persistentSurfaceId(); private: - void updatePanelHeightHack(Qt::WindowState); + void updateSurfaceState(); mutable QMutex mMutex; const WId mId; - const QSharedPointer<QMirClientClipboard> mClipboard; - std::unique_ptr<QMirClientSurface> mSurface; + Qt::WindowState mWindowState; + Qt::WindowFlags mWindowFlags; + bool mWindowVisible; + bool mWindowExposed; + QMirClientAppStateController *mAppStateController; + QMirClientDebugExtension *mDebugExtention; + QMirClientNativeInterface *mNativeInterface; + std::unique_ptr<UbuntuSurface> mSurface; + float mScale; + MirFormFactor mFormFactor; }; #endif // QMIRCLIENTWINDOW_H diff --git a/src/plugins/platforms/platforms.pro b/src/plugins/platforms/platforms.pro index 2a6e059243..9ccc2b54b9 100644 --- a/src/plugins/platforms/platforms.pro +++ b/src/plugins/platforms/platforms.pro @@ -36,7 +36,7 @@ qtConfig(directfb) { qtConfig(linuxfb): SUBDIRS += linuxfb -unix:!android:!darwin: SUBDIRS += vnc +qtConfig(vnc): SUBDIRS += vnc freebsd { SUBDIRS += bsdfb diff --git a/src/plugins/platforms/qnx/qnx.pro b/src/plugins/platforms/qnx/qnx.pro index 9da3d6811b..0b052adf0f 100644 --- a/src/plugins/platforms/qnx/qnx.pro +++ b/src/plugins/platforms/qnx/qnx.pro @@ -7,8 +7,6 @@ QT += \ # Uncomment this to build with support for IMF once it becomes available in the BBNDK #CONFIG += qqnx_imf -CONFIG += qqnx_screeneventthread - # Uncomment these to enable debugging output for various aspects of the plugin #DEFINES += QQNXBUFFER_DEBUG #DEFINES += QQNXBUTTON_DEBUG @@ -47,7 +45,8 @@ SOURCES = main.cpp \ qqnxservices.cpp \ qqnxcursor.cpp \ qqnxrasterwindow.cpp \ - qqnxglobal.cpp + qqnxglobal.cpp \ + qqnxscreeneventthread.cpp HEADERS = main.h \ qqnxbuffer.h \ @@ -67,13 +66,8 @@ HEADERS = main.h \ qqnxrasterwindow.h \ qqnxscreeneventfilter.h \ qqnxglobal.h \ - qqnxlgmon.h - -CONFIG(qqnx_screeneventthread) { - DEFINES += QQNX_SCREENEVENTTHREAD - SOURCES += qqnxscreeneventthread.cpp - HEADERS += qqnxscreeneventthread.h -} + qqnxlgmon.h \ + qqnxscreeneventthread.h LIBS += -lscreen diff --git a/src/plugins/platforms/qnx/qqnxintegration.cpp b/src/plugins/platforms/qnx/qqnxintegration.cpp index 7229d7d2a8..eee0581709 100644 --- a/src/plugins/platforms/qnx/qqnxintegration.cpp +++ b/src/plugins/platforms/qnx/qqnxintegration.cpp @@ -40,9 +40,7 @@ #include "qqnxglobal.h" #include "qqnxintegration.h" -#if defined(QQNX_SCREENEVENTTHREAD) #include "qqnxscreeneventthread.h" -#endif #include "qqnxnativeinterface.h" #include "qqnxrasterbackingstore.h" #include "qqnxscreen.h" @@ -125,9 +123,7 @@ static inline QQnxIntegration::Options parseOptions(const QStringList ¶mList QQnxIntegration::QQnxIntegration(const QStringList ¶mList) : QPlatformIntegration() -#if defined(QQNX_SCREENEVENTTHREAD) , m_screenEventThread(0) -#endif , m_navigatorEventHandler(new QQnxNavigatorEventHandler()) , m_virtualKeyboard(0) #if defined(QQNX_PPS) @@ -169,10 +165,8 @@ QQnxIntegration::QQnxIntegration(const QStringList ¶mList) #endif // Create/start event thread -#if defined(QQNX_SCREENEVENTTHREAD) m_screenEventThread = new QQnxScreenEventThread(ms_screenContext, m_screenEventHandler); m_screenEventThread->start(); -#endif #if defined(QQNX_PPS) // Create/start the keyboard class. @@ -235,10 +229,8 @@ QQnxIntegration::~QQnxIntegration() #endif delete m_navigatorEventHandler; -#if defined(QQNX_SCREENEVENTTHREAD) // Stop/destroy screen event thread delete m_screenEventThread; -#endif // In case the event-dispatcher was never transferred to QCoreApplication delete m_eventDispatcher; diff --git a/src/plugins/platforms/qnx/qqnxintegration.h b/src/plugins/platforms/qnx/qqnxintegration.h index 6f2af82100..b2008baa0c 100644 --- a/src/plugins/platforms/qnx/qqnxintegration.h +++ b/src/plugins/platforms/qnx/qqnxintegration.h @@ -48,9 +48,7 @@ QT_BEGIN_NAMESPACE -#if defined(QQNX_SCREENEVENTTHREAD) class QQnxScreenEventThread; -#endif class QQnxFileDialogHelper; class QQnxNativeInterface; class QQnxWindow; @@ -142,9 +140,7 @@ private: static void removeWindow(screen_window_t qnxWindow); static screen_context_t ms_screenContext; -#if defined(QQNX_SCREENEVENTTHREAD) QQnxScreenEventThread *m_screenEventThread; -#endif QQnxNavigatorEventHandler *m_navigatorEventHandler; QQnxAbstractVirtualKeyboard *m_virtualKeyboard; #if defined(QQNX_PPS) diff --git a/src/plugins/platforms/qnx/qqnxscreeneventhandler.cpp b/src/plugins/platforms/qnx/qqnxscreeneventhandler.cpp index beda6e1a49..5d230e2145 100644 --- a/src/plugins/platforms/qnx/qqnxscreeneventhandler.cpp +++ b/src/plugins/platforms/qnx/qqnxscreeneventhandler.cpp @@ -40,9 +40,7 @@ #include "qqnxglobal.h" #include "qqnxscreeneventhandler.h" -#if defined(QQNX_SCREENEVENTTHREAD) #include "qqnxscreeneventthread.h" -#endif #include "qqnxintegration.h" #include "qqnxkeytranslator.h" #include "qqnxscreen.h" @@ -67,9 +65,7 @@ QQnxScreenEventHandler::QQnxScreenEventHandler(QQnxIntegration *integration) , m_lastButtonState(Qt::NoButton) , m_lastMouseWindow(0) , m_touchDevice(0) -#if defined(QQNX_SCREENEVENTTHREAD) , m_eventThread(0) -#endif , m_focusLostTimer(-1) { // Create a touch device @@ -198,7 +194,6 @@ void QQnxScreenEventHandler::injectKeyboardEvent(int flags, int sym, int modifie } } -#if defined(QQNX_SCREENEVENTTHREAD) void QQnxScreenEventHandler::setScreenEventThread(QQnxScreenEventThread *eventThread) { m_eventThread = eventThread; @@ -233,7 +228,6 @@ void QQnxScreenEventHandler::processEventsFromScreenThread() m_eventThread->unlock(); } -#endif void QQnxScreenEventHandler::handleKeyboardEvent(screen_event_t event) { diff --git a/src/plugins/platforms/qnx/qqnxscreeneventhandler.h b/src/plugins/platforms/qnx/qqnxscreeneventhandler.h index 80798a8a2d..d872f9b9aa 100644 --- a/src/plugins/platforms/qnx/qqnxscreeneventhandler.h +++ b/src/plugins/platforms/qnx/qqnxscreeneventhandler.h @@ -48,9 +48,7 @@ QT_BEGIN_NAMESPACE class QQnxIntegration; class QQnxScreenEventFilter; -#if defined(QQNX_SCREENEVENTTHREAD) class QQnxScreenEventThread; -#endif class QQnxScreenEventHandler : public QObject { @@ -66,9 +64,7 @@ public: static void injectKeyboardEvent(int flags, int sym, int mod, int scan, int cap); -#if defined(QQNX_SCREENEVENTTHREAD) void setScreenEventThread(QQnxScreenEventThread *eventThread); -#endif Q_SIGNALS: void newWindowCreated(void *window); @@ -77,10 +73,8 @@ Q_SIGNALS: protected: void timerEvent(QTimerEvent *event) override; -#if defined(QQNX_SCREENEVENTTHREAD) private Q_SLOTS: void processEventsFromScreenThread(); -#endif private: void handleKeyboardEvent(screen_event_t event); @@ -105,9 +99,7 @@ private: QTouchDevice *m_touchDevice; QWindowSystemInterface::TouchPoint m_touchPoints[MaximumTouchPoints]; QList<QQnxScreenEventFilter*> m_eventFilters; -#if defined(QQNX_SCREENEVENTTHREAD) QQnxScreenEventThread *m_eventThread; -#endif int m_focusLostTimer; }; diff --git a/src/plugins/platforms/vnc/main.cpp b/src/plugins/platforms/vnc/main.cpp index 6ee8bf1ec6..3ec0f0b78d 100644 --- a/src/plugins/platforms/vnc/main.cpp +++ b/src/plugins/platforms/vnc/main.cpp @@ -48,7 +48,7 @@ class QVncIntegrationPlugin : public QPlatformIntegrationPlugin Q_OBJECT Q_PLUGIN_METADATA(IID QPlatformIntegrationFactoryInterface_iid FILE "vnc.json") public: - QPlatformIntegration *create(const QString&, const QStringList&) Q_DECL_OVERRIDE; + QPlatformIntegration *create(const QString&, const QStringList&) override; }; QPlatformIntegration* QVncIntegrationPlugin::create(const QString& system, const QStringList& paramList) diff --git a/src/plugins/platforms/vnc/qvnc.cpp b/src/plugins/platforms/vnc/qvnc.cpp index a45bb1c19c..fa65e8c9a4 100644 --- a/src/plugins/platforms/vnc/qvnc.cpp +++ b/src/plugins/platforms/vnc/qvnc.cpp @@ -531,13 +531,12 @@ void QRfbRawEncoder::write() socket->flush(); } +#if QT_CONFIG(cursor) QVncClientCursor::QVncClientCursor() { -#ifndef QT_NO_CURSOR QWindow *w = QGuiApplication::focusWindow(); QCursor c = w ? w->cursor() : QCursor(Qt::ArrowCursor); changeCursor(&c, 0); -#endif } QVncClientCursor::~QVncClientCursor() @@ -587,7 +586,6 @@ void QVncClientCursor::write(QVncClient *client) const void QVncClientCursor::changeCursor(QCursor *widgetCursor, QWindow *window) { Q_UNUSED(window); -#ifndef QT_NO_CURSOR const Qt::CursorShape shape = widgetCursor ? widgetCursor->shape() : Qt::ArrowCursor; if (shape == Qt::BitmapCursor) { @@ -601,9 +599,6 @@ void QVncClientCursor::changeCursor(QCursor *widgetCursor, QWindow *window) cursor = *platformImage.image(); hotspot = platformImage.hotspot(); } -#else // !QT_NO_CURSOR - Q_UNUSED(widgetCursor); -#endif for (auto client : clients) client->setDirtyCursor(); } @@ -619,6 +614,7 @@ uint QVncClientCursor::removeClient(QVncClient *client) clients.removeOne(client); return clients.count(); } +#endif // QT_CONFIG(cursor) QVncServer::QVncServer(QVncScreen *screen, quint16 port) : qvnc_screen(screen) diff --git a/src/plugins/platforms/vnc/qvnc_p.h b/src/plugins/platforms/vnc/qvnc_p.h index 1c44cd1569..338fae9f87 100644 --- a/src/plugins/platforms/vnc/qvnc_p.h +++ b/src/plugins/platforms/vnc/qvnc_p.h @@ -95,7 +95,7 @@ public: QVncDirtyMapOptimized(QVncScreen *screen) : QVncDirtyMap(screen) {} ~QVncDirtyMapOptimized() {} - void setDirty(int x, int y, bool force = false); + void setDirty(int x, int y, bool force = false) override; }; @@ -216,7 +216,7 @@ class QRfbRawEncoder : public QRfbEncoder public: QRfbRawEncoder(QVncClient *s) : QRfbEncoder(s) {} - void write(); + void write() override; private: QByteArray buffer; @@ -364,6 +364,7 @@ private: friend class QRfbMultiColorHextile<SRC>; }; +#if QT_CONFIG(cursor) class QVncClientCursor : public QPlatformCursor { public: @@ -372,7 +373,7 @@ public: void write(QVncClient *client) const; - void changeCursor(QCursor *widgetCursor, QWindow *window); + void changeCursor(QCursor *widgetCursor, QWindow *window) override; void addClient(QVncClient *client); uint removeClient(QVncClient *client); @@ -381,7 +382,7 @@ public: QPoint hotspot; QVector<QVncClient *> clients; }; - +#endif // QT_CONFIG(cursor) class QVncServer : public QObject { diff --git a/src/plugins/platforms/vnc/qvncclient.cpp b/src/plugins/platforms/vnc/qvncclient.cpp index 58dcfc9b51..9dfe873927 100644 --- a/src/plugins/platforms/vnc/qvncclient.cpp +++ b/src/plugins/platforms/vnc/qvncclient.cpp @@ -425,14 +425,14 @@ void QVncClient::checkUpdate() { if (!m_wantUpdate) return; - +#if QT_CONFIG(cursor) if (m_dirtyCursor) { m_server->screen()->clientCursor->write(this); m_dirtyCursor = false; m_wantUpdate = false; return; } - +#endif if (!m_dirtyRegion.isEmpty()) { if (m_encoder) m_encoder->write(); diff --git a/src/plugins/platforms/vnc/qvncintegration.h b/src/plugins/platforms/vnc/qvncintegration.h index 293ff54376..34a6a6b941 100644 --- a/src/plugins/platforms/vnc/qvncintegration.h +++ b/src/plugins/platforms/vnc/qvncintegration.h @@ -55,19 +55,19 @@ public: QVncIntegration(const QStringList ¶mList); ~QVncIntegration(); - void initialize() Q_DECL_OVERRIDE; - bool hasCapability(QPlatformIntegration::Capability cap) const Q_DECL_OVERRIDE; + void initialize() override; + bool hasCapability(QPlatformIntegration::Capability cap) const override; - QPlatformWindow *createPlatformWindow(QWindow *window) const Q_DECL_OVERRIDE; - QPlatformBackingStore *createPlatformBackingStore(QWindow *window) const Q_DECL_OVERRIDE; + QPlatformWindow *createPlatformWindow(QWindow *window) const override; + QPlatformBackingStore *createPlatformBackingStore(QWindow *window) const override; - QAbstractEventDispatcher *createEventDispatcher() const Q_DECL_OVERRIDE; + QAbstractEventDispatcher *createEventDispatcher() const override; - QPlatformFontDatabase *fontDatabase() const Q_DECL_OVERRIDE; - QPlatformServices *services() const Q_DECL_OVERRIDE; - QPlatformInputContext *inputContext() const Q_DECL_OVERRIDE { return m_inputContext; } + QPlatformFontDatabase *fontDatabase() const override; + QPlatformServices *services() const override; + QPlatformInputContext *inputContext() const override { return m_inputContext; } - QPlatformNativeInterface *nativeInterface() const Q_DECL_OVERRIDE; + QPlatformNativeInterface *nativeInterface() const override; QList<QPlatformScreen *> screens() const; diff --git a/src/plugins/platforms/vnc/qvncscreen.cpp b/src/plugins/platforms/vnc/qvncscreen.cpp index 64f1bc0bf7..cd43ce4e69 100644 --- a/src/plugins/platforms/vnc/qvncscreen.cpp +++ b/src/plugins/platforms/vnc/qvncscreen.cpp @@ -58,8 +58,10 @@ QVncScreen::QVncScreen(const QStringList &args) QVncScreen::~QVncScreen() { +#if QT_CONFIG(cursor) if (clientCursor) delete clientCursor; +#endif } bool QVncScreen::initialize() @@ -120,17 +122,21 @@ QRegion QVncScreen::doRedraw() return touched; } + void QVncScreen::enableClientCursor(QVncClient *client) { +#if QT_CONFIG(cursor) delete mCursor; mCursor = nullptr; if (!clientCursor) clientCursor = new QVncClientCursor(); clientCursor->addClient(client); +#endif } void QVncScreen::disableClientCursor(QVncClient *client) { +#if QT_CONFIG(cursor) uint clientCount = clientCursor->removeClient(client); if (clientCount == 0) { delete clientCursor; @@ -138,11 +144,16 @@ void QVncScreen::disableClientCursor(QVncClient *client) } mCursor = new QFbCursor(this); +#endif } QPlatformCursor *QVncScreen::cursor() const { +#if QT_CONFIG(cursor) return mCursor ? static_cast<QPlatformCursor *>(mCursor) : static_cast<QPlatformCursor *>(clientCursor); +#else + return nullptr; +#endif } // grabWindow() grabs "from the screen" not from the backingstores. @@ -151,10 +162,10 @@ QPixmap QVncScreen::grabWindow(WId wid, int x, int y, int width, int height) con { if (!wid) { if (width < 0) - width = mScreenImage->width() - x; + width = mScreenImage.width() - x; if (height < 0) - height = mScreenImage->height() - y; - return QPixmap::fromImage(*mScreenImage).copy(x, y, width, height); + height = mScreenImage.height() - y; + return QPixmap::fromImage(mScreenImage).copy(x, y, width, height); } QFbWindow *window = windowForId(wid); @@ -166,7 +177,7 @@ QPixmap QVncScreen::grabWindow(WId wid, int x, int y, int width, int height) con height = geom.height() - y; QRect rect(geom.topLeft() + QPoint(x, y), QSize(width, height)); rect &= window->geometry(); - return QPixmap::fromImage(*mScreenImage).copy(rect); + return QPixmap::fromImage(mScreenImage).copy(rect); } return QPixmap(); @@ -188,5 +199,10 @@ bool QVncScreen::swapBytes() const } #endif +QFbScreen::Flags QVncScreen::flags() const +{ + return QFbScreen::DontForceFirstWindowToFullScreen; +} + QT_END_NAMESPACE diff --git a/src/plugins/platforms/vnc/qvncscreen.h b/src/plugins/platforms/vnc/qvncscreen.h index 0b42c3c7ea..e69aa90d41 100644 --- a/src/plugins/platforms/vnc/qvncscreen.h +++ b/src/plugins/platforms/vnc/qvncscreen.h @@ -59,16 +59,18 @@ public: QVncScreen(const QStringList &args); ~QVncScreen(); - bool initialize(); + bool initialize() override; - QPixmap grabWindow(WId wid, int x, int y, int width, int height) const Q_DECL_OVERRIDE; + QPixmap grabWindow(WId wid, int x, int y, int width, int height) const override; - QRegion doRedraw() Q_DECL_OVERRIDE; - QImage *image() const { return mScreenImage; } + QRegion doRedraw() override; + QImage *image() { return &mScreenImage; } void enableClientCursor(QVncClient *client); void disableClientCursor(QVncClient *client); - QPlatformCursor *cursor() const Q_DECL_OVERRIDE; + QPlatformCursor *cursor() const override; + + Flags flags() const override; void clearDirty() { dirtyRegion = QRegion(); } @@ -84,7 +86,9 @@ public: QRegion dirtyRegion; int refreshRate = 30; QVncServer *vncServer = 0; +#if QT_CONFIG(cursor) QVncClientCursor *clientCursor = 0; +#endif }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/windows/accessible/qwindowsaccessibility.h b/src/plugins/platforms/windows/accessible/qwindowsaccessibility.h index e035e3924a..8621e93120 100644 --- a/src/plugins/platforms/windows/accessible/qwindowsaccessibility.h +++ b/src/plugins/platforms/windows/accessible/qwindowsaccessibility.h @@ -53,7 +53,7 @@ class QWindowsAccessibility : public QPlatformAccessibility public: QWindowsAccessibility(); static bool handleAccessibleObjectFromWindowRequest(HWND hwnd, WPARAM wParam, LPARAM lParam, LRESULT *lResult); - void notifyAccessibilityUpdate(QAccessibleEvent *event) Q_DECL_OVERRIDE; + void notifyAccessibilityUpdate(QAccessibleEvent *event) override; static IAccessible *wrap(QAccessibleInterface *acc); static QWindow *windowHelper(const QAccessibleInterface *iface); }; diff --git a/src/plugins/platforms/windows/accessible/qwindowsmsaaaccessible.cpp b/src/plugins/platforms/windows/accessible/qwindowsmsaaaccessible.cpp index 85aab84c2c..25b1577772 100644 --- a/src/plugins/platforms/windows/accessible/qwindowsmsaaaccessible.cpp +++ b/src/plugins/platforms/windows/accessible/qwindowsmsaaaccessible.cpp @@ -1052,11 +1052,24 @@ HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::get_accValue(VARIANT varID, BS return S_FALSE; } -HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::put_accValue(VARIANT, BSTR) +HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::put_accValue(VARIANT, BSTR value) { QAccessibleInterface *accessible = accessibleInterface(); accessibleDebugClientCalls(accessible); - return DISP_E_MEMBERNOTFOUND; + + if (!accessible || !accessible->isValid()) { + return E_FAIL; + } + + QString qstrValue = QString::fromWCharArray(value); + + if (accessible->valueInterface()) { + accessible->valueInterface()->setCurrentValue(qstrValue); + } else { + accessible->setText(QAccessible::Value, qstrValue); + } + + return S_OK; } // moz: [important] diff --git a/src/plugins/platforms/windows/openglblacklists/default.json b/src/plugins/platforms/windows/openglblacklists/default.json index dd99e674ec..69f4a54d05 100644 --- a/src/plugins/platforms/windows/openglblacklists/default.json +++ b/src/plugins/platforms/windows/openglblacklists/default.json @@ -114,6 +114,18 @@ "features": [ "disable_desktopgl" ] - } + }, + { + "id": 10, + "description": "Intel(R) HD Graphics IronLake (Arrandale) crashes on makeCurrent QTBUG-53888", + "vendor_id": "0x8086", + "device_id": [ "0x0046" ], + "os": { + "type": "win" + }, + "features": [ + "disable_desktopgl" + ] + } ] } diff --git a/src/plugins/platforms/windows/qtwindowsglobal.h b/src/plugins/platforms/windows/qtwindowsglobal.h index ec6a8f62ae..e703b5d47e 100644 --- a/src/plugins/platforms/windows/qtwindowsglobal.h +++ b/src/plugins/platforms/windows/qtwindowsglobal.h @@ -56,6 +56,10 @@ # define WM_GESTURE 0x0119 #endif +#ifndef WM_DPICHANGED +# define WM_DPICHANGED 0x02E0 +#endif + QT_BEGIN_NAMESPACE namespace QtWindows @@ -96,12 +100,14 @@ enum WindowsEventType // Simplify event types FocusInEvent = WindowEventFlag + 17, FocusOutEvent = WindowEventFlag + 18, WhatsThisEvent = WindowEventFlag + 19, + DpiChangedEvent = WindowEventFlag + 21, MouseEvent = MouseEventFlag + 1, MouseWheelEvent = MouseEventFlag + 2, CursorEvent = MouseEventFlag + 3, TouchEvent = TouchEventFlag + 1, NonClientMouseEvent = NonClientEventFlag + MouseEventFlag + 1, NonClientHitTest = NonClientEventFlag + 2, + NonClientCreate = NonClientEventFlag + 3, KeyEvent = KeyEventFlag + 1, KeyDownEvent = KeyEventFlag + KeyDownEventFlag + 1, KeyboardLayoutChangeEvent = KeyEventFlag + 2, @@ -114,6 +120,7 @@ enum WindowsEventType // Simplify event types QueryEndSessionApplicationEvent = ApplicationEventFlag + 4, EndSessionApplicationEvent = ApplicationEventFlag + 5, AppCommandEvent = ApplicationEventFlag + 6, + DeviceChangeEvent = ApplicationEventFlag + 7, InputMethodStartCompositionEvent = InputMethodEventFlag + 1, InputMethodCompositionEvent = InputMethodEventFlag + 2, InputMethodEndCompositionEvent = InputMethodEventFlag + 3, @@ -177,6 +184,8 @@ inline QtWindows::WindowsEventType windowsEventType(UINT message, WPARAM wParamI return QtWindows::HideEvent; case WM_SIZE: return QtWindows::ResizeEvent; + case WM_NCCREATE: + return QtWindows::NonClientCreate; case WM_NCCALCSIZE: return QtWindows::CalculateSize; case WM_NCHITTEST: @@ -263,6 +272,10 @@ inline QtWindows::WindowsEventType windowsEventType(UINT message, WPARAM wParamI #endif case WM_GESTURE: return QtWindows::GestureEvent; + case WM_DEVICECHANGE: + return QtWindows::DeviceChangeEvent; + case WM_DPICHANGED: + return QtWindows::DpiChangedEvent; default: break; } diff --git a/src/plugins/platforms/windows/qwindowsbackingstore.h b/src/plugins/platforms/windows/qwindowsbackingstore.h index 46a7fcc676..9e62266697 100644 --- a/src/plugins/platforms/windows/qwindowsbackingstore.h +++ b/src/plugins/platforms/windows/qwindowsbackingstore.h @@ -57,15 +57,15 @@ public: QWindowsBackingStore(QWindow *window); ~QWindowsBackingStore(); - QPaintDevice *paintDevice() Q_DECL_OVERRIDE; - void flush(QWindow *window, const QRegion ®ion, const QPoint &offset) Q_DECL_OVERRIDE; - void resize(const QSize &size, const QRegion &r) Q_DECL_OVERRIDE; - bool scroll(const QRegion &area, int dx, int dy) Q_DECL_OVERRIDE; - void beginPaint(const QRegion &) Q_DECL_OVERRIDE; + QPaintDevice *paintDevice() override; + void flush(QWindow *window, const QRegion ®ion, const QPoint &offset) override; + void resize(const QSize &size, const QRegion &r) override; + bool scroll(const QRegion &area, int dx, int dy) override; + void beginPaint(const QRegion &) override; HDC getDC() const; - QImage toImage() const Q_DECL_OVERRIDE; + QImage toImage() const override; private: QScopedPointer<QWindowsNativeImage> m_image; diff --git a/src/plugins/platforms/windows/qwindowsclipboard.cpp b/src/plugins/platforms/windows/qwindowsclipboard.cpp index d4a7e27762..01191a7dc1 100644 --- a/src/plugins/platforms/windows/qwindowsclipboard.cpp +++ b/src/plugins/platforms/windows/qwindowsclipboard.cpp @@ -81,7 +81,7 @@ static QDebug operator<<(QDebug d, const QMimeData *mimeData) d << "QMimeData("; if (mimeData) { const QStringList formats = mimeData->formats(); - d << "formats=" << formats.join(QStringLiteral(", ")); + d << "formats=" << formats.join(QLatin1String(", ")); if (mimeData->hasText()) d << ", text=" << mimeData->text(); if (mimeData->hasHtml()) @@ -149,8 +149,7 @@ static void cleanClipboardPostRoutine() QWindowsClipboard *QWindowsClipboard::m_instance = 0; -QWindowsClipboard::QWindowsClipboard() : - m_data(0), m_clipboardViewer(0), m_nextClipboardViewer(0), m_formatListenerRegistered(false) +QWindowsClipboard::QWindowsClipboard() { QWindowsClipboard::m_instance = this; qAddPostRoutine(cleanClipboardPostRoutine); @@ -322,7 +321,7 @@ void QWindowsClipboard::setMimeData(QMimeData *mimeData, QClipboard::Mode mode) const HRESULT src = OleSetClipboard(m_data); if (src != S_OK) { QString mimeDataFormats = mimeData ? - mimeData->formats().join(QStringLiteral(", ")) : QString(QStringLiteral("NULL")); + mimeData->formats().join(QLatin1String(", ")) : QString(QStringLiteral("NULL")); qErrnoWarning("OleSetClipboard: Failed to set mime data (%s) on clipboard: %s", qPrintable(mimeDataFormats), QWindowsContext::comErrorString(src).constData()); diff --git a/src/plugins/platforms/windows/qwindowsclipboard.h b/src/plugins/platforms/windows/qwindowsclipboard.h index 992d34d492..4f3e7437f6 100644 --- a/src/plugins/platforms/windows/qwindowsclipboard.h +++ b/src/plugins/platforms/windows/qwindowsclipboard.h @@ -52,8 +52,8 @@ class QWindowsClipboardRetrievalMimeData : public QWindowsInternalMimeData { public: protected: - IDataObject *retrieveDataObject() const Q_DECL_OVERRIDE; - void releaseDataObject(IDataObject *) const Q_DECL_OVERRIDE; + IDataObject *retrieveDataObject() const override; + void releaseDataObject(IDataObject *) const override; }; class QWindowsClipboard : public QPlatformClipboard @@ -64,10 +64,10 @@ public: void registerViewer(); // Call in initialization, when context is up. void cleanup(); - QMimeData *mimeData(QClipboard::Mode mode = QClipboard::Clipboard) Q_DECL_OVERRIDE; - void setMimeData(QMimeData *data, QClipboard::Mode mode = QClipboard::Clipboard) Q_DECL_OVERRIDE; - bool supportsMode(QClipboard::Mode mode) const Q_DECL_OVERRIDE; - bool ownsMode(QClipboard::Mode mode) const Q_DECL_OVERRIDE; + QMimeData *mimeData(QClipboard::Mode mode = QClipboard::Clipboard) override; + void setMimeData(QMimeData *data, QClipboard::Mode mode = QClipboard::Clipboard) override; + bool supportsMode(QClipboard::Mode mode) const override; + bool ownsMode(QClipboard::Mode mode) const override; inline bool clipboardViewerWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam, LRESULT *result); @@ -85,10 +85,10 @@ private: static QWindowsClipboard *m_instance; QWindowsClipboardRetrievalMimeData m_retrievalData; - QWindowsOleDataObject *m_data; - HWND m_clipboardViewer; - HWND m_nextClipboardViewer; - bool m_formatListenerRegistered; + QWindowsOleDataObject *m_data = nullptr; + HWND m_clipboardViewer = 0; + HWND m_nextClipboardViewer = 0; + bool m_formatListenerRegistered = false; }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/windows/qwindowscontext.cpp b/src/plugins/platforms/windows/qwindowscontext.cpp index bb9ed730a3..b7a866679f 100644 --- a/src/plugins/platforms/windows/qwindowscontext.cpp +++ b/src/plugins/platforms/windows/qwindowscontext.cpp @@ -68,6 +68,7 @@ #include <QtCore/QHash> #include <QtCore/QStringList> #include <QtCore/QDebug> +#include <QtCore/QOperatingSystemVersion> #include <QtCore/QSysInfo> #include <QtCore/QScopedArrayPointer> #include <QtCore/private/qsystemlibrary_p.h> @@ -78,6 +79,7 @@ #include <stdio.h> #include <windowsx.h> #include <comdef.h> +#include <dbt.h> QT_BEGIN_NAMESPACE @@ -127,6 +129,28 @@ static inline QWindowsSessionManager *platformSessionManager() { } #endif +static inline int windowDpiAwareness(HWND hwnd) +{ + return QWindowsContext::user32dll.getWindowDpiAwarenessContext && QWindowsContext::user32dll.getWindowDpiAwarenessContext + ? QWindowsContext::user32dll.getAwarenessFromDpiAwarenessContext(QWindowsContext::user32dll.getWindowDpiAwarenessContext(hwnd)) + : -1; +} + +// Note: This only works within WM_NCCREATE +static bool enableNonClientDpiScaling(HWND hwnd) +{ + bool result = false; + if (QWindowsContext::user32dll.enableNonClientDpiScaling && windowDpiAwareness(hwnd) == 2) { + result = QWindowsContext::user32dll.enableNonClientDpiScaling(hwnd) != FALSE; + if (!result) { + const DWORD errorCode = GetLastError(); + qErrnoWarning(int(errorCode), "EnableNonClientDpiScaling() failed for HWND %p (%lu)", + hwnd, errorCode); + } + } + return result; +} + /*! \class QWindowsUser32DLL \brief Struct that contains dynamically resolved symbols of User32.dll. @@ -142,14 +166,6 @@ static inline QWindowsSessionManager *platformSessionManager() { \internal \ingroup qt-lighthouse-win */ -QWindowsUser32DLL::QWindowsUser32DLL() : - isTouchWindow(0), - registerTouchWindow(0), unregisterTouchWindow(0), - getTouchInputInfo(0), closeTouchInputHandle(0), setProcessDPIAware(0), - addClipboardFormatListener(0), removeClipboardFormatListener(0), - getDisplayAutoRotationPreferences(0), setDisplayAutoRotationPreferences(0) -{ -} void QWindowsUser32DLL::init() { @@ -161,6 +177,12 @@ void QWindowsUser32DLL::init() getDisplayAutoRotationPreferences = (GetDisplayAutoRotationPreferences)library.resolve("GetDisplayAutoRotationPreferences"); setDisplayAutoRotationPreferences = (SetDisplayAutoRotationPreferences)library.resolve("SetDisplayAutoRotationPreferences"); + + if (QSysInfo::windowsVersion() >= QSysInfo::WV_WINDOWS10) { // Appears in 10.0.14393, October 2016 + enableNonClientDpiScaling = (EnableNonClientDpiScaling)library.resolve("EnableNonClientDpiScaling"); + getWindowDpiAwarenessContext = (GetWindowDpiAwarenessContext)library.resolve("GetWindowDpiAwarenessContext"); + getAwarenessFromDpiAwarenessContext = (GetAwarenessFromDpiAwarenessContext)library.resolve("GetAwarenessFromDpiAwarenessContext"); + } } bool QWindowsUser32DLL::initTouch() @@ -176,16 +198,9 @@ bool QWindowsUser32DLL::initTouch() return isTouchWindow && registerTouchWindow && unregisterTouchWindow && getTouchInputInfo && closeTouchInputHandle; } -QWindowsShcoreDLL::QWindowsShcoreDLL() - : getProcessDpiAwareness(0) - , setProcessDpiAwareness(0) - , getDpiForMonitor(0) -{ -} - void QWindowsShcoreDLL::init() { - if (QSysInfo::windowsVersion() < QSysInfo::WV_WINDOWS8_1) + if (QOperatingSystemVersion::current() < QOperatingSystemVersion::Windows8_1) return; QSystemLibrary library(QStringLiteral("SHCore")); getProcessDpiAwareness = (GetProcessDpiAwareness)library.resolve("GetProcessDpiAwareness"); @@ -211,14 +226,13 @@ QWindowsContext *QWindowsContext::m_instance = 0; typedef QHash<HWND, QWindowsWindow *> HandleBaseWindowHash; struct QWindowsContextPrivate { - QWindowsContextPrivate(); - unsigned m_systemInfo; + unsigned m_systemInfo = 0; QSet<QString> m_registeredWindowClassNames; HandleBaseWindowHash m_windows; - HDC m_displayContext; - int m_defaultDPI; + HDC m_displayContext = 0; + int m_defaultDPI = 96; QWindowsKeyMapper m_keyMapper; QWindowsMouseHandler m_mouseHandler; QWindowsMimeConverter m_mimeConverter; @@ -229,15 +243,13 @@ struct QWindowsContextPrivate { #endif const HRESULT m_oleInitializeResult; const QByteArray m_eventType; - QWindow *m_lastActiveWindow; - bool m_asyncExpose; + QWindow *m_lastActiveWindow = nullptr; + bool m_asyncExpose = false; }; QWindowsContextPrivate::QWindowsContextPrivate() - : m_systemInfo(0) - , m_oleInitializeResult(OleInitialize(NULL)) + : m_oleInitializeResult(OleInitialize(NULL)) , m_eventType(QByteArrayLiteral("windows_generic_MSG")) - , m_lastActiveWindow(0), m_asyncExpose(0) { QWindowsContext::user32dll.init(); QWindowsContext::shcoredll.init(); @@ -311,6 +323,13 @@ bool QWindowsContext::initTouch(unsigned integrationOptions) QWindowSystemInterface::registerTouchDevice(touchDevice); d->m_systemInfo |= QWindowsContext::SI_SupportsTouch; + + // A touch device was plugged while the app is running. Register all windows for touch. + if (QGuiApplicationPrivate::is_app_running) { + for (QWindowsWindow *w : qAsConst(d->m_windows)) + w->registerTouchWindow(); + } + return true; } @@ -379,6 +398,11 @@ void QWindowsContext::setWindowCreationContext(const QSharedPointer<QWindowCreat d->m_creationContext = ctx; } +QSharedPointer<QWindowCreationContext> QWindowsContext::windowCreationContext() const +{ + return d->m_creationContext; +} + int QWindowsContext::defaultDPI() const { return d->m_defaultDPI; @@ -807,7 +831,9 @@ static inline QWindowsInputContext *windowsInputContext() bool QWindowsContext::windowsProc(HWND hwnd, UINT message, QtWindows::WindowsEventType et, - WPARAM wParam, LPARAM lParam, LRESULT *result) + WPARAM wParam, LPARAM lParam, + LRESULT *result, + QWindowsWindow **platformWindowPtr) { *result = 0; @@ -838,6 +864,7 @@ bool QWindowsContext::windowsProc(HWND hwnd, UINT message, } QWindowsWindow *platformWindow = findPlatformWindow(hwnd); + *platformWindowPtr = platformWindow; if (platformWindow) { filterResult = 0; if (QWindowSystemInterface::handleNativeEvent(platformWindow->window(), d->m_eventType, &msg, &filterResult)) { @@ -919,6 +946,10 @@ bool QWindowsContext::windowsProc(HWND hwnd, UINT message, case QtWindows::MoveEvent: d->m_creationContext->obtainedGeometry.moveTo(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)); return true; + case QtWindows::NonClientCreate: + if (QSysInfo::windowsVersion() >= QSysInfo::WV_WINDOWS10 && d->m_creationContext->window->isTopLevel()) + enableNonClientDpiScaling(msg.hwnd); + return false; case QtWindows::CalculateSize: return QWindowsGeometryHint::handleCalculateSize(d->m_creationContext->customMargins, msg, result); case QtWindows::GeometryChangingEvent: @@ -942,6 +973,13 @@ bool QWindowsContext::windowsProc(HWND hwnd, UINT message, } switch (et) { + case QtWindows::DeviceChangeEvent: + if (d->m_systemInfo & QWindowsContext::SI_SupportsTouch) + break; + // See if there are any touch devices added + if (wParam == DBT_DEVNODES_CHANGED) + initTouch(); + break; case QtWindows::KeyboardLayoutChangeEvent: if (QWindowsInputContext *wic = windowsInputContext()) wic->handleInputLanguageChanged(wParam, lParam); @@ -1026,9 +1064,6 @@ bool QWindowsContext::windowsProc(HWND hwnd, UINT message, return true; case QtWindows::ThemeChanged: { // Switch from Aero to Classic changes margins. - const Qt::WindowFlags flags = platformWindow->window()->flags(); - if ((flags & Qt::WindowType_Mask) != Qt::Desktop && !(flags & Qt::FramelessWindowHint)) - platformWindow->setFlag(QWindowsWindow::FrameDirty); if (QWindowsTheme *theme = QWindowsTheme::instance()) theme->windowsThemeChanged(platformWindow->window()); return true; @@ -1068,6 +1103,15 @@ bool QWindowsContext::windowsProc(HWND hwnd, UINT message, return true; #endif } break; + case QtWindows::DpiChangedEvent: { + platformWindow->setFlag(QWindowsWindow::WithinDpiChanged); + const RECT *prcNewWindow = reinterpret_cast<RECT *>(lParam); + SetWindowPos(hwnd, NULL, prcNewWindow->left, prcNewWindow->top, + prcNewWindow->right - prcNewWindow->left, + prcNewWindow->bottom - prcNewWindow->top, SWP_NOZORDER | SWP_NOACTIVATE); + platformWindow->clearFlag(QWindowsWindow::WithinDpiChanged); + return true; + } #if !defined(QT_NO_SESSIONMANAGER) case QtWindows::QueryEndSessionApplicationEvent: { QWindowsSessionManager *sessionManager = platformSessionManager(); @@ -1201,6 +1245,37 @@ QTouchDevice *QWindowsContext::touchDevice() const return d->m_mouseHandler.touchDevice(); } +static inline bool isEmptyRect(const RECT &rect) +{ + return rect.right - rect.left == 0 && rect.bottom - rect.top == 0; +} + +static inline QMargins marginsFromRects(const RECT &frame, const RECT &client) +{ + return QMargins(client.left - frame.left, client.top - frame.top, + frame.right - client.right, frame.bottom - client.bottom); +} + +static RECT rectFromNcCalcSize(UINT message, WPARAM wParam, LPARAM lParam, int n) +{ + RECT result = {0, 0, 0, 0}; + if (message == WM_NCCALCSIZE && wParam) + result = reinterpret_cast<const NCCALCSIZE_PARAMS *>(lParam)->rgrc[n]; + return result; +} + +static inline bool isMinimized(HWND hwnd) +{ + WINDOWPLACEMENT windowPlacement; + windowPlacement.length = sizeof(WINDOWPLACEMENT); + return GetWindowPlacement(hwnd, &windowPlacement) && windowPlacement.showCmd == SW_SHOWMINIMIZED; +} + +static inline bool isTopLevel(HWND hwnd) +{ + return (GetWindowLongPtr(hwnd, GWL_STYLE) & WS_CHILD) == 0; +} + /*! \brief Windows functions for actual windows. @@ -1214,7 +1289,9 @@ extern "C" LRESULT QT_WIN_CALLBACK qWindowsWndProc(HWND hwnd, UINT message, WPAR { LRESULT result; const QtWindows::WindowsEventType et = windowsEventType(message, wParam, lParam); - const bool handled = QWindowsContext::instance()->windowsProc(hwnd, message, et, wParam, lParam, &result); + QWindowsWindow *platformWindow = nullptr; + const RECT ncCalcSizeFrame = rectFromNcCalcSize(message, wParam, lParam, 0); + const bool handled = QWindowsContext::instance()->windowsProc(hwnd, message, et, wParam, lParam, &result, &platformWindow); if (QWindowsContext::verbose > 1 && lcQpaEvents().isDebugEnabled()) { if (const char *eventName = QWindowsGuiEventDispatcher::windowsMessageName(message)) { qCDebug(lcQpaEvents) << "EVENT: hwd=" << hwnd << eventName << hex << "msg=0x" << message @@ -1224,6 +1301,24 @@ extern "C" LRESULT QT_WIN_CALLBACK qWindowsWndProc(HWND hwnd, UINT message, WPAR } if (!handled) result = DefWindowProc(hwnd, message, wParam, lParam); + + // Capture WM_NCCALCSIZE on top level windows and obtain the window margins by + // subtracting the rectangles before and after processing. This will correctly + // capture client code overriding the message and allow for per-monitor margins + // for High DPI (QTBUG-53255, QTBUG-40578). + if (message == WM_NCCALCSIZE && !isEmptyRect(ncCalcSizeFrame) && isTopLevel(hwnd) && !isMinimized(hwnd)) { + const QMargins margins = + marginsFromRects(ncCalcSizeFrame, rectFromNcCalcSize(message, wParam, lParam, 0)); + if (margins.left() >= 0) { + if (platformWindow) { + platformWindow->setFrameMargins(margins); + } else { + const QSharedPointer<QWindowCreationContext> ctx = QWindowsContext::instance()->windowCreationContext(); + if (!ctx.isNull()) + ctx->margins = margins; + } + } + } return result; } diff --git a/src/plugins/platforms/windows/qwindowscontext.h b/src/plugins/platforms/windows/qwindowscontext.h index 9dfde67797..b50010321b 100644 --- a/src/plugins/platforms/windows/qwindowscontext.h +++ b/src/plugins/platforms/windows/qwindowscontext.h @@ -80,7 +80,6 @@ class QTouchDevice; struct QWindowsUser32DLL { - QWindowsUser32DLL(); inline void init(); inline bool initTouch(); @@ -94,30 +93,36 @@ struct QWindowsUser32DLL typedef BOOL (WINAPI *RemoveClipboardFormatListener)(HWND); typedef BOOL (WINAPI *GetDisplayAutoRotationPreferences)(DWORD *); typedef BOOL (WINAPI *SetDisplayAutoRotationPreferences)(DWORD); + typedef BOOL (WINAPI *EnableNonClientDpiScaling)(HWND); + typedef int (WINAPI *GetWindowDpiAwarenessContext)(HWND); + typedef int (WINAPI *GetAwarenessFromDpiAwarenessContext)(int); // Touch functions from Windows 7 onwards (also for use with Q_CC_MSVC). - IsTouchWindow isTouchWindow; - RegisterTouchWindow registerTouchWindow; - UnregisterTouchWindow unregisterTouchWindow; - GetTouchInputInfo getTouchInputInfo; - CloseTouchInputHandle closeTouchInputHandle; + IsTouchWindow isTouchWindow = nullptr; + RegisterTouchWindow registerTouchWindow = nullptr; + UnregisterTouchWindow unregisterTouchWindow = nullptr; + GetTouchInputInfo getTouchInputInfo = nullptr; + CloseTouchInputHandle closeTouchInputHandle = nullptr; // Windows Vista onwards - SetProcessDPIAware setProcessDPIAware; + SetProcessDPIAware setProcessDPIAware = nullptr; // Clipboard listeners are present on Windows Vista onwards // but missing in MinGW 4.9 stub libs. Can be removed in MinGW 5. - AddClipboardFormatListener addClipboardFormatListener; - RemoveClipboardFormatListener removeClipboardFormatListener; + AddClipboardFormatListener addClipboardFormatListener = nullptr; + RemoveClipboardFormatListener removeClipboardFormatListener = nullptr; // Rotation API - GetDisplayAutoRotationPreferences getDisplayAutoRotationPreferences; - SetDisplayAutoRotationPreferences setDisplayAutoRotationPreferences; + GetDisplayAutoRotationPreferences getDisplayAutoRotationPreferences = nullptr; + SetDisplayAutoRotationPreferences setDisplayAutoRotationPreferences = nullptr; + + EnableNonClientDpiScaling enableNonClientDpiScaling = nullptr; + GetWindowDpiAwarenessContext getWindowDpiAwarenessContext = nullptr; + GetAwarenessFromDpiAwarenessContext getAwarenessFromDpiAwarenessContext = nullptr; }; // Shell scaling library (Windows 8.1 onwards) struct QWindowsShcoreDLL { - QWindowsShcoreDLL(); void init(); inline bool isValid() const { return getProcessDpiAwareness && setProcessDpiAwareness && getDpiForMonitor; } @@ -125,9 +130,9 @@ struct QWindowsShcoreDLL { typedef HRESULT (WINAPI *SetProcessDpiAwareness)(int); typedef HRESULT (WINAPI *GetDpiForMonitor)(HMONITOR,int,UINT *,UINT *); - GetProcessDpiAwareness getProcessDpiAwareness; - SetProcessDpiAwareness setProcessDpiAwareness; - GetDpiForMonitor getDpiForMonitor; + GetProcessDpiAwareness getProcessDpiAwareness = nullptr; + SetProcessDpiAwareness setProcessDpiAwareness = nullptr; + GetDpiForMonitor getDpiForMonitor = nullptr; }; class QWindowsContext @@ -181,12 +186,14 @@ public: inline bool windowsProc(HWND hwnd, UINT message, QtWindows::WindowsEventType et, - WPARAM wParam, LPARAM lParam, LRESULT *result); + WPARAM wParam, LPARAM lParam, LRESULT *result, + QWindowsWindow **platformWindowPtr); QWindow *keyGrabber() const; void setKeyGrabber(QWindow *hwnd); void setWindowCreationContext(const QSharedPointer<QWindowCreationContext> &ctx); + QSharedPointer<QWindowCreationContext> windowCreationContext() const; void setTabletAbsoluteRange(int a); void setProcessDpiAwareness(QtWindows::ProcessDpiAwareness dpiAwareness); diff --git a/src/plugins/platforms/windows/qwindowscursor.h b/src/plugins/platforms/windows/qwindowscursor.h index 6fff5f9ab1..df2e22733b 100644 --- a/src/plugins/platforms/windows/qwindowscursor.h +++ b/src/plugins/platforms/windows/qwindowscursor.h @@ -104,9 +104,9 @@ public: explicit QWindowsCursor(const QPlatformScreen *screen); - void changeCursor(QCursor * widgetCursor, QWindow * widget) Q_DECL_OVERRIDE; - QPoint pos() const Q_DECL_OVERRIDE; - void setPos(const QPoint &pos) Q_DECL_OVERRIDE; + void changeCursor(QCursor * widgetCursor, QWindow * widget) override; + QPoint pos() const override; + void setPos(const QPoint &pos) override; static HCURSOR createPixmapCursor(QPixmap pixmap, const QPoint &hotSpot, qreal scaleFactor = 1); static HCURSOR createPixmapCursor(const PixmapCursor &pc, qreal scaleFactor = 1) { return createPixmapCursor(pc.pixmap, pc.hotSpot, scaleFactor); } diff --git a/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp b/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp index 8f1358de6c..f4527bcc60 100644 --- a/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp +++ b/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp @@ -66,9 +66,11 @@ #include <QtCore/QMutexLocker> #include <QtCore/QUuid> #include <QtCore/QRegularExpression> +#include <QtCore/QTemporaryFile> #include <QtCore/private/qsystemlibrary_p.h> #include <algorithm> +#include <vector> #include <QtCore/qt_windows.h> @@ -212,15 +214,6 @@ private: */ template <class BaseClass> -QWindowsDialogHelperBase<BaseClass>::QWindowsDialogHelperBase() : - m_nativeDialog(0), - m_ownerWindow(0), - m_timerId(0), - m_thread(0) -{ -} - -template <class BaseClass> void QWindowsDialogHelperBase<BaseClass>::cleanupThread() { if (m_thread) { // Thread may be running if the dialog failed to close. @@ -549,11 +542,11 @@ public: IFACEMETHODIMP OnOverwrite(IFileDialog *, IShellItem *, FDE_OVERWRITE_RESPONSE *) { return S_OK; } QWindowsNativeFileDialogEventHandler(QWindowsNativeFileDialogBase *nativeFileDialog) : - m_ref(1), m_nativeFileDialog(nativeFileDialog) {} + m_nativeFileDialog(nativeFileDialog) {} virtual ~QWindowsNativeFileDialogEventHandler() {} private: - long m_ref; + long m_ref = 1; QWindowsNativeFileDialogBase *m_nativeFileDialog; }; @@ -570,6 +563,235 @@ IFileDialogEvents *QWindowsNativeFileDialogEventHandler::create(QWindowsNativeFi } /*! + \class QWindowsShellItem + \brief Wrapper for IShellItem + + \sa QWindowsNativeFileDialogBase + \internal + \ingroup qt-lighthouse-win +*/ +class QWindowsShellItem +{ +public: + typedef std::vector<IShellItem *> IShellItems; + + explicit QWindowsShellItem(IShellItem *item); + + SFGAOF attributes() const { return m_attributes; } + QString normalDisplay() const // base name, usually + { return displayName(m_item, SIGDN_NORMALDISPLAY); } + QString desktopAbsoluteParsing() const + { return displayName(m_item, SIGDN_DESKTOPABSOLUTEPARSING); } + QString path() const; // Only set for 'FileSystem' (SFGAO_FILESYSTEM) items + QUrl url() const; + + bool isFileSystem() const { return (m_attributes & SFGAO_FILESYSTEM) != 0; } + bool isDir() const { return (m_attributes & SFGAO_FOLDER) != 0; } + // Copy using IFileOperation + bool canCopy() const { return (m_attributes & SFGAO_CANCOPY) != 0; } + // Supports IStream + bool canStream() const { return (m_attributes & SFGAO_STREAM) != 0; } + + bool copyData(QIODevice *out); + + static IShellItems itemsFromItemArray(IShellItemArray *items); + +#ifndef QT_NO_DEBUG_STREAM + void format(QDebug &d) const; +#endif + +private: + static QString displayName(IShellItem *item, SIGDN mode); + static QString libraryItemDefaultSaveFolder(IShellItem *item); + QUrl urlValue() const; + + IShellItem *m_item; + SFGAOF m_attributes; +}; + +QWindowsShellItem::QWindowsShellItem(IShellItem *item) + : m_item(item) + , m_attributes(0) +{ + if (FAILED(item->GetAttributes(SFGAO_CAPABILITYMASK | SFGAO_DISPLAYATTRMASK | SFGAO_CONTENTSMASK | SFGAO_STORAGECAPMASK, &m_attributes))) + m_attributes = 0; +} + +QString QWindowsShellItem::path() const +{ + if (isFileSystem()) + return QDir::cleanPath(QWindowsShellItem::displayName(m_item, SIGDN_FILESYSPATH)); + // Check for a "Library" item (Windows 7) + if (QSysInfo::windowsVersion() >= QSysInfo::WV_WINDOWS7 && isDir()) + return QWindowsShellItem::libraryItemDefaultSaveFolder(m_item); + return QString(); +} + +QUrl QWindowsShellItem::urlValue() const // plain URL as returned by SIGDN_URL, not set for all items +{ + QUrl result; + const QString urlString = displayName(m_item, SIGDN_URL); + if (!urlString.isEmpty()) { + const QUrl parsed = QUrl(urlString); + if (parsed.isValid()) { + result = parsed; + } else { + qWarning("%s: Unable to decode URL \"%s\": %s", __FUNCTION__, + qPrintable(urlString), qPrintable(parsed.errorString())); + } + } + return result; +} + +QUrl QWindowsShellItem::url() const +{ + // Prefer file if existent to avoid any misunderstandings about UNC shares + const QString fsPath = path(); + if (!fsPath.isEmpty()) + return QUrl::fromLocalFile(fsPath); + const QUrl urlV = urlValue(); + if (urlV.isValid()) + return urlV; + // Last resort: encode the absolute desktop parsing id as data URL + const QString data = QStringLiteral("data:text/plain;base64,") + + QLatin1String(desktopAbsoluteParsing().toLatin1().toBase64()); + return QUrl(data); +} + +QString QWindowsShellItem::displayName(IShellItem *item, SIGDN mode) +{ + LPWSTR name = nullptr; + QString result; + if (SUCCEEDED(item->GetDisplayName(mode, &name))) { + result = QString::fromWCharArray(name); + CoTaskMemFree(name); + } + return result; +} + +QWindowsShellItem::IShellItems QWindowsShellItem::itemsFromItemArray(IShellItemArray *items) +{ + IShellItems result; + DWORD itemCount = 0; + if (FAILED(items->GetCount(&itemCount)) || itemCount == 0) + return result; + result.reserve(itemCount); + for (DWORD i = 0; i < itemCount; ++i) { + IShellItem *item = nullptr; + if (SUCCEEDED(items->GetItemAt(i, &item))) + result.push_back(item); + } + return result; +} + +bool QWindowsShellItem::copyData(QIODevice *out) +{ + if (!canCopy() || !canStream()) + return false; + IStream *istream = nullptr; + HRESULT hr = m_item->BindToHandler(NULL, BHID_Stream, IID_PPV_ARGS(&istream)); + if (FAILED(hr)) + return false; + enum : ULONG { bufSize = 102400 }; + char buffer[bufSize]; + ULONG bytesRead; + forever { + bytesRead = 0; + hr = istream->Read(buffer, bufSize, &bytesRead); // S_FALSE: EOF reached + if ((hr == S_OK || hr == S_FALSE) && bytesRead) + out->write(buffer, bytesRead); + else + break; + } + istream->Release(); + return hr == S_OK || hr == S_FALSE; +} + +// Helper for "Libraries": collections of folders appearing from Windows 7 +// on, visible in the file dialogs. + +// Load a library from a IShellItem (sanitized copy of the inline function +// SHLoadLibraryFromItem from ShObjIdl.h, which does not exist for MinGW). +static IShellLibrary *sHLoadLibraryFromItem(IShellItem *libraryItem, DWORD mode) +{ + // ID symbols present from Windows 7 on: + static const CLSID classId_ShellLibrary = {0xd9b3211d, 0xe57f, 0x4426, {0xaa, 0xef, 0x30, 0xa8, 0x6, 0xad, 0xd3, 0x97}}; + static const IID iId_IShellLibrary = {0x11a66efa, 0x382e, 0x451a, {0x92, 0x34, 0x1e, 0xe, 0x12, 0xef, 0x30, 0x85}}; + + IShellLibrary *helper = nullptr; + IShellLibrary *result = nullptr; + if (SUCCEEDED(CoCreateInstance(classId_ShellLibrary, NULL, CLSCTX_INPROC_SERVER, iId_IShellLibrary, reinterpret_cast<void **>(&helper)))) + if (SUCCEEDED(helper->LoadLibraryFromItem(libraryItem, mode))) + helper->QueryInterface(iId_IShellLibrary, reinterpret_cast<void **>(&result)); + if (helper) + helper->Release(); + return result; +} + +// Return default save folders of a library-type item. +QString QWindowsShellItem::libraryItemDefaultSaveFolder(IShellItem *item) +{ + QString result; + if (IShellLibrary *library = sHLoadLibraryFromItem(item, STGM_READ | STGM_SHARE_DENY_WRITE)) { + IShellItem *item = Q_NULLPTR; + if (SUCCEEDED(library->GetDefaultSaveFolder(DSFT_DETECT, IID_IShellItem, reinterpret_cast<void **>(&item)))) { + result = QDir::cleanPath(QWindowsShellItem::displayName(item, SIGDN_FILESYSPATH)); + item->Release(); + } + library->Release(); + } + return result; +} + +#ifndef QT_NO_DEBUG_STREAM +void QWindowsShellItem::format(QDebug &d) const +{ + d << "attributes=0x" << hex << attributes() << dec; + if (isFileSystem()) + d << " [filesys]"; + if (isDir()) + d << " [dir]"; + if (canStream()) + d << " [stream]"; + if (canCopy()) + d << " [copyable]"; + d << ", normalDisplay=\"" << normalDisplay() + << "\", desktopAbsoluteParsing=\"" << desktopAbsoluteParsing() << '"'; + const QString pathS = path(); + if (!pathS.isEmpty()) + d << ", path=\"" << pathS << '"'; + const QUrl urlV = urlValue(); + if (urlV.isValid()) + d << "\", url=" << urlV; +} + +QDebug operator<<(QDebug d, const QWindowsShellItem &i) +{ + QDebugStateSaver saver(d); + d.nospace(); + d.noquote(); + d << "QShellItem("; + i.format(d); + d << ')'; + return d; +} + +QDebug operator<<(QDebug d, IShellItem *i) +{ + QDebugStateSaver saver(d); + d.nospace(); + d.noquote(); + d << "IShellItem(" << static_cast<const void *>(i); + if (i) { + d << ", "; + QWindowsShellItem(i).format(d); + } + d << ')'; + return d; +} +#endif // !QT_NO_DEBUG_STREAM + +/*! \class QWindowsNativeFileDialogBase \brief Windows native file dialog wrapper around IFileOpenDialog, IFileSaveDialog. @@ -590,12 +812,12 @@ public: inline static QWindowsNativeFileDialogBase *create(QFileDialogOptions::AcceptMode am, const QWindowsFileDialogSharedData &data); - void setWindowTitle(const QString &title) Q_DECL_OVERRIDE; + void setWindowTitle(const QString &title) override; inline void setMode(QFileDialogOptions::FileMode mode, QFileDialogOptions::AcceptMode acceptMode, QFileDialogOptions::FileDialogOptions options); inline void setDirectory(const QUrl &directory); inline void updateDirectory() { setDirectory(m_data.directory()); } inline QString directory() const; - void doExec(HWND owner = 0) Q_DECL_OVERRIDE; + void doExec(HWND owner = 0) override; virtual void setNameFilters(const QStringList &f); inline void selectNameFilter(const QString &filter); inline void updateSelectedNameFilter() { selectNameFilter(m_data.selectedNameFilter()); } @@ -624,36 +846,31 @@ signals: void filterSelected(const QString & filter); public slots: - void close() Q_DECL_OVERRIDE; + void close() override; protected: explicit QWindowsNativeFileDialogBase(const QWindowsFileDialogSharedData &data); bool init(const CLSID &clsId, const IID &iid); void setDefaultSuffixSys(const QString &s); inline IFileDialog * fileDialog() const { return m_fileDialog; } - static QString itemPath(IShellItem *item); - static QList<QUrl> libraryItemFolders(IShellItem *item); - static QString libraryItemDefaultSaveFolder(IShellItem *item); - static int itemPaths(IShellItemArray *items, QList<QUrl> *fileResult = 0); static IShellItem *shellItem(const QUrl &url); const QWindowsFileDialogSharedData &data() const { return m_data; } QWindowsFileDialogSharedData &data() { return m_data; } private: - IFileDialog *m_fileDialog; - IFileDialogEvents *m_dialogEvents; - DWORD m_cookie; + IFileDialog *m_fileDialog = nullptr; + IFileDialogEvents *m_dialogEvents = nullptr; + DWORD m_cookie = 0; QStringList m_nameFilters; - bool m_hideFiltersDetails; - bool m_hasDefaultSuffix; + bool m_hideFiltersDetails = false; + bool m_hasDefaultSuffix = false; QWindowsFileDialogSharedData m_data; QString m_title; }; QWindowsNativeFileDialogBase::QWindowsNativeFileDialogBase(const QWindowsFileDialogSharedData &data) : - m_fileDialog(0), m_dialogEvents(0), m_cookie(0), m_hideFiltersDetails(false), - m_hasDefaultSuffix(false), m_data(data) + m_data(data) { } @@ -753,7 +970,7 @@ QString QWindowsNativeFileDialogBase::directory() const QString result; IShellItem *item = 0; if (m_fileDialog && SUCCEEDED(m_fileDialog->GetFolder(&item)) && item) { - result = QWindowsNativeFileDialogBase::itemPath(item); + result = QWindowsShellItem(item).path(); item->Release(); } return result; @@ -807,113 +1024,6 @@ void QWindowsNativeFileDialogBase::setMode(QFileDialogOptions::FileMode mode, qErrnoWarning("%s: SetOptions() failed", __FUNCTION__); } -#if defined(__IShellLibrary_INTERFACE_DEFINED__) // Windows SDK 7 - -// Helper for "Libraries": collections of folders appearing from Windows 7 -// on, visible in the file dialogs. - -// Load a library from a IShellItem (sanitized copy of the inline function -// SHLoadLibraryFromItem from ShObjIdl.h, which does not exist for MinGW). -static IShellLibrary *sHLoadLibraryFromItem(IShellItem *libraryItem, DWORD mode) -{ - // ID symbols present from Windows 7 on: - static const CLSID classId_ShellLibrary = {0xd9b3211d, 0xe57f, 0x4426, {0xaa, 0xef, 0x30, 0xa8, 0x6, 0xad, 0xd3, 0x97}}; - static const IID iId_IShellLibrary = {0x11a66efa, 0x382e, 0x451a, {0x92, 0x34, 0x1e, 0xe, 0x12, 0xef, 0x30, 0x85}}; - - IShellLibrary *helper = 0; - IShellLibrary *result = 0; - if (SUCCEEDED(CoCreateInstance(classId_ShellLibrary, NULL, CLSCTX_INPROC_SERVER, iId_IShellLibrary, reinterpret_cast<void **>(&helper)))) - if (SUCCEEDED(helper->LoadLibraryFromItem(libraryItem, mode))) - helper->QueryInterface(iId_IShellLibrary, reinterpret_cast<void **>(&result)); - if (helper) - helper->Release(); - return result; -} - -// Return all folders of a library-type item. -QList<QUrl> QWindowsNativeFileDialogBase::libraryItemFolders(IShellItem *item) -{ - QList<QUrl> result; - if (IShellLibrary *library = sHLoadLibraryFromItem(item, STGM_READ | STGM_SHARE_DENY_WRITE)) { - IShellItemArray *itemArray = 0; - if (SUCCEEDED(library->GetFolders(LFF_FORCEFILESYSTEM, IID_IShellItemArray, reinterpret_cast<void **>(&itemArray)))) { - QWindowsNativeFileDialogBase::itemPaths(itemArray, &result); - itemArray->Release(); - } - library->Release(); - } - return result; -} - -// Return default save folders of a library-type item. -QString QWindowsNativeFileDialogBase::libraryItemDefaultSaveFolder(IShellItem *item) -{ - QString result; - if (IShellLibrary *library = sHLoadLibraryFromItem(item, STGM_READ | STGM_SHARE_DENY_WRITE)) { - IShellItem *item = 0; - if (SUCCEEDED(library->GetDefaultSaveFolder(DSFT_DETECT, IID_IShellItem, reinterpret_cast<void **>(&item)))) { - result = QWindowsNativeFileDialogBase::itemPath(item); - item->Release(); - } - library->Release(); - } - return result; -} - -#else // __IShellLibrary_INTERFACE_DEFINED__ - -QList<QUrl> QWindowsNativeFileDialogBase::libraryItemFolders(IShellItem *) -{ - return QList<QUrl>(); -} - -QString QWindowsNativeFileDialogBase::libraryItemDefaultSaveFolder(IShellItem *) -{ - return QString(); -} - -#endif // !__IShellLibrary_INTERFACE_DEFINED__ - -QString QWindowsNativeFileDialogBase::itemPath(IShellItem *item) -{ - SFGAOF attributes = 0; - // Check whether it has a file system representation? - if (FAILED(item->GetAttributes(SFGAO_FILESYSTEM, &attributes))) - return QString(); - if (attributes & SFGAO_FILESYSTEM) { - LPWSTR name = 0; - QString result; - if (SUCCEEDED(item->GetDisplayName(SIGDN_FILESYSPATH, &name))) { - result = QDir::cleanPath(QString::fromWCharArray(name)); - CoTaskMemFree(name); - } - return result; - } - // Check for a "Library" item - if ((QSysInfo::windowsVersion() & QSysInfo::WV_NT_based) && QSysInfo::windowsVersion() >= QSysInfo::WV_WINDOWS7) - return QWindowsNativeFileDialogBase::libraryItemDefaultSaveFolder(item); - return QString(); -} - -int QWindowsNativeFileDialogBase::itemPaths(IShellItemArray *items, - QList<QUrl> *result /* = 0 */) -{ - DWORD itemCount = 0; - if (result) - result->clear(); - if (FAILED(items->GetCount(&itemCount))) - return 0; - if (result && itemCount) { - result->reserve(itemCount); - for (DWORD i = 0; i < itemCount; ++i) { - IShellItem *item = 0; - if (SUCCEEDED(items->GetItemAt(i, &item))) - result->push_back(QUrl::fromLocalFile(QWindowsNativeFileDialogBase::itemPath(item))); - } - } - return itemCount; -} - // Split a list of name filters into description and actual filters struct FilterSpec { @@ -1011,6 +1121,13 @@ void QWindowsNativeFileDialogBase::setDefaultSuffixSys(const QString &s) m_fileDialog->SetDefaultExtension(wSuffix); } +static inline IFileDialog2 *getFileDialog2(IFileDialog *fileDialog) +{ + IFileDialog2 *result; + return SUCCEEDED(fileDialog->QueryInterface(IID_IFileDialog2, reinterpret_cast<void **>(&result))) + ? result : nullptr; +} + void QWindowsNativeFileDialogBase::setLabelText(QFileDialogOptions::DialogLabel l, const QString &text) { wchar_t *wText = const_cast<wchar_t *>(reinterpret_cast<const wchar_t *>(text.utf16())); @@ -1021,8 +1138,13 @@ void QWindowsNativeFileDialogBase::setLabelText(QFileDialogOptions::DialogLabel case QFileDialogOptions::Accept: m_fileDialog->SetOkButtonLabel(wText); break; - case QFileDialogOptions::LookIn: case QFileDialogOptions::Reject: + if (IFileDialog2 *dialog2 = getFileDialog2(m_fileDialog)) { + dialog2->SetCancelButtonLabel(wText); + dialog2->Release(); + } + break; + case QFileDialogOptions::LookIn: case QFileDialogOptions::FileType: case QFileDialogOptions::DialogLabelCount: break; @@ -1067,7 +1189,7 @@ void QWindowsNativeFileDialogBase::selectNameFilter(const QString &filter) if (index < 0) { qWarning("%s: Invalid parameter '%s' not found in '%s'.", __FUNCTION__, qPrintable(filter), - qPrintable(m_nameFilters.join(QStringLiteral(", ")))); + qPrintable(m_nameFilters.join(QLatin1String(", ")))); return; } m_fileDialog->SetFileTypeIndex(index + 1); // one-based. @@ -1087,7 +1209,7 @@ QString QWindowsNativeFileDialogBase::selectedNameFilter() const void QWindowsNativeFileDialogBase::onFolderChange(IShellItem *item) { if (item) { - const QUrl directory = QUrl::fromLocalFile(QWindowsNativeFileDialogBase::itemPath(item)); + const QUrl directory = QWindowsShellItem(item).url(); m_data.setDirectory(directory); emit directoryEntered(directory); } @@ -1165,9 +1287,9 @@ class QWindowsNativeSaveFileDialog : public QWindowsNativeFileDialogBase public: explicit QWindowsNativeSaveFileDialog(const QWindowsFileDialogSharedData &data) : QWindowsNativeFileDialogBase(data) {} - void setNameFilters(const QStringList &f) Q_DECL_OVERRIDE; - QList<QUrl> selectedFiles() const Q_DECL_OVERRIDE; - QList<QUrl> dialogResult() const Q_DECL_OVERRIDE; + void setNameFilters(const QStringList &f) override; + QList<QUrl> selectedFiles() const override; + QList<QUrl> dialogResult() const override; }; // Return the first suffix from the name filter "Foo files (*.foo;*.bar)" -> "foo". @@ -1210,7 +1332,7 @@ QList<QUrl> QWindowsNativeSaveFileDialog::dialogResult() const QList<QUrl> result; IShellItem *item = 0; if (SUCCEEDED(fileDialog()->GetResult(&item)) && item) - result.push_back(QUrl::fromLocalFile(QWindowsNativeFileDialogBase::itemPath(item))); + result.append(QWindowsShellItem(item).url()); return result; } @@ -1220,7 +1342,7 @@ QList<QUrl> QWindowsNativeSaveFileDialog::selectedFiles() const IShellItem *item = 0; const HRESULT hr = fileDialog()->GetCurrentSelection(&item); if (SUCCEEDED(hr) && item) { - result.push_back(QUrl::fromLocalFile(QWindowsNativeSaveFileDialog::itemPath(item))); + result.append(QWindowsShellItem(item).url()); item->Release(); } return result; @@ -1241,20 +1363,69 @@ class QWindowsNativeOpenFileDialog : public QWindowsNativeFileDialogBase public: explicit QWindowsNativeOpenFileDialog(const QWindowsFileDialogSharedData &data) : QWindowsNativeFileDialogBase(data) {} - QList<QUrl> selectedFiles() const Q_DECL_OVERRIDE; - QList<QUrl> dialogResult() const Q_DECL_OVERRIDE; + QList<QUrl> selectedFiles() const override; + QList<QUrl> dialogResult() const override; private: inline IFileOpenDialog *openFileDialog() const { return static_cast<IFileOpenDialog *>(fileDialog()); } }; +// Helpers for managing a list of temporary copies of items with no +// file system representation (SFGAO_FILESYSTEM unset, for example devices +// using MTP) returned by IFileOpenDialog. This emulates the behavior +// of the Win32 API GetOpenFileName() used in Qt 4 (QTBUG-57070). + +Q_GLOBAL_STATIC(QStringList, temporaryItemCopies) + +static void cleanupTemporaryItemCopies() +{ + for (const QString &file : qAsConst(*temporaryItemCopies())) + QFile::remove(file); +} + +static QString createTemporaryItemCopy(QWindowsShellItem &qItem) +{ + if (!qItem.canCopy() || !qItem.canStream()) + return QString(); + QString pattern = qItem.normalDisplay(); + const int lastDot = pattern.lastIndexOf(QLatin1Char('.')); + const QString placeHolder = QStringLiteral("_XXXXXX"); + if (lastDot >= 0) + pattern.insert(lastDot, placeHolder); + else + pattern.append(placeHolder); + + QTemporaryFile targetFile(QDir::tempPath() + QLatin1Char('/') + pattern); + targetFile.setAutoRemove(false); + if (!targetFile.open() || !qItem.copyData(&targetFile)) + return QString(); + const QString result = targetFile.fileName(); + if (temporaryItemCopies()->isEmpty()) + qAddPostRoutine(cleanupTemporaryItemCopies); + temporaryItemCopies()->append(result); + return result; +} + QList<QUrl> QWindowsNativeOpenFileDialog::dialogResult() const { QList<QUrl> result; IShellItemArray *items = 0; - if (SUCCEEDED(openFileDialog()->GetResults(&items)) && items) - QWindowsNativeFileDialogBase::itemPaths(items, &result); + if (SUCCEEDED(openFileDialog()->GetResults(&items)) && items) { + for (IShellItem *item : QWindowsShellItem::itemsFromItemArray(items)) { + QWindowsShellItem qItem(item); + const QString path = qItem.path(); + if (path.isEmpty()) { + const QString temporaryCopy = createTemporaryItemCopy(qItem); + if (temporaryCopy.isEmpty()) + qWarning() << "Unable to create a local copy of" << qItem; + else + result.append(QUrl::fromLocalFile(temporaryCopy)); + } else { + result.append(qItem.url()); + } + } + } return result; } @@ -1263,8 +1434,16 @@ QList<QUrl> QWindowsNativeOpenFileDialog::selectedFiles() const QList<QUrl> result; IShellItemArray *items = 0; const HRESULT hr = openFileDialog()->GetSelectedItems(&items); - if (SUCCEEDED(hr) && items) - QWindowsNativeFileDialogBase::itemPaths(items, &result); + if (SUCCEEDED(hr) && items) { + for (IShellItem *item : QWindowsShellItem::itemsFromItemArray(items)) { + const QWindowsShellItem qItem(item); + const QUrl url = qItem.url(); + if (url.isValid()) + result.append(url); + else + qWarning().nospace() << __FUNCTION__<< ": Unable to obtain URL of " << qItem; + } + } return result; } @@ -1309,19 +1488,19 @@ class QWindowsFileDialogHelper : public QWindowsDialogHelperBase<QPlatformFileDi { public: QWindowsFileDialogHelper() {} - virtual bool supportsNonModalDialog(const QWindow * /* parent */ = 0) const Q_DECL_OVERRIDE { return false; } - virtual bool defaultNameFilterDisables() const Q_DECL_OVERRIDE + bool supportsNonModalDialog(const QWindow * /* parent */ = 0) const override { return false; } + bool defaultNameFilterDisables() const override { return false; } - virtual void setDirectory(const QUrl &directory) Q_DECL_OVERRIDE; - virtual QUrl directory() const Q_DECL_OVERRIDE; - virtual void selectFile(const QUrl &filename) Q_DECL_OVERRIDE; - virtual QList<QUrl> selectedFiles() const Q_DECL_OVERRIDE; - virtual void setFilter() Q_DECL_OVERRIDE; - virtual void selectNameFilter(const QString &filter) Q_DECL_OVERRIDE; - virtual QString selectedNameFilter() const Q_DECL_OVERRIDE; + void setDirectory(const QUrl &directory) override; + QUrl directory() const override; + void selectFile(const QUrl &filename) override; + QList<QUrl> selectedFiles() const override; + void setFilter() override; + void selectNameFilter(const QString &filter) override; + QString selectedNameFilter() const override; private: - QWindowsNativeDialogBase *createNativeDialog() Q_DECL_OVERRIDE; + QWindowsNativeDialogBase *createNativeDialog() override; inline QWindowsNativeFileDialogBase *nativeFileDialog() const { return static_cast<QWindowsNativeFileDialogBase *>(nativeDialog()); } @@ -1357,6 +1536,8 @@ QWindowsNativeDialogBase *QWindowsFileDialogHelper::createNativeDialog() result->setLabelText(QFileDialogOptions::FileName, opts->labelText(QFileDialogOptions::FileName)); if (opts->isLabelExplicitlySet(QFileDialogOptions::Accept)) result->setLabelText(QFileDialogOptions::Accept, opts->labelText(QFileDialogOptions::Accept)); + if (opts->isLabelExplicitlySet(QFileDialogOptions::Reject)) + result->setLabelText(QFileDialogOptions::Reject, opts->labelText(QFileDialogOptions::Reject)); result->updateDirectory(); result->updateSelectedNameFilter(); const QList<QUrl> initialSelection = opts->initiallySelectedFiles(); @@ -1447,13 +1628,13 @@ public: static QWindowsXpNativeFileDialog *create(const OptionsPtr &options, const QWindowsFileDialogSharedData &data); - void setWindowTitle(const QString &t) Q_DECL_OVERRIDE { m_title = t; } - void doExec(HWND owner = 0) Q_DECL_OVERRIDE; + void setWindowTitle(const QString &t) override { m_title = t; } + void doExec(HWND owner = 0) override; int existingDirCallback(HWND hwnd, UINT uMsg, LPARAM lParam); public slots: - void close() Q_DECL_OVERRIDE {} + void close() override {} private: typedef BOOL (APIENTRY *PtrGetOpenFileNameW)(LPOPENFILENAMEW); @@ -1689,19 +1870,19 @@ class QWindowsXpFileDialogHelper : public QWindowsDialogHelperBase<QPlatformFile { public: QWindowsXpFileDialogHelper() {} - bool supportsNonModalDialog(const QWindow * /* parent */ = 0) const Q_DECL_OVERRIDE { return false; } - bool defaultNameFilterDisables() const Q_DECL_OVERRIDE + bool supportsNonModalDialog(const QWindow * /* parent */ = 0) const override { return false; } + bool defaultNameFilterDisables() const override { return true; } - void setDirectory(const QUrl &directory) Q_DECL_OVERRIDE; - QUrl directory() const Q_DECL_OVERRIDE; - void selectFile(const QUrl &url) Q_DECL_OVERRIDE; - QList<QUrl> selectedFiles() const Q_DECL_OVERRIDE; - void setFilter() Q_DECL_OVERRIDE {} - void selectNameFilter(const QString &) Q_DECL_OVERRIDE; - QString selectedNameFilter() const Q_DECL_OVERRIDE; + void setDirectory(const QUrl &directory) override; + QUrl directory() const override; + void selectFile(const QUrl &url) override; + QList<QUrl> selectedFiles() const override; + void setFilter() override {} + void selectNameFilter(const QString &) override; + QString selectedNameFilter() const override; private: - QWindowsNativeDialogBase *createNativeDialog() Q_DECL_OVERRIDE; + QWindowsNativeDialogBase *createNativeDialog() override; inline QWindowsXpNativeFileDialog *nativeFileDialog() const { return static_cast<QWindowsXpNativeFileDialog *>(nativeDialog()); } @@ -1773,13 +1954,13 @@ public: explicit QWindowsNativeColorDialog(const SharedPointerColor &color); - void setWindowTitle(const QString &) Q_DECL_OVERRIDE {} + void setWindowTitle(const QString &) override {} public slots: - void close() Q_DECL_OVERRIDE {} + void close() override {} private: - void doExec(HWND owner = 0) Q_DECL_OVERRIDE; + void doExec(HWND owner = 0) override; COLORREF m_customColors[CustomColorCount]; QPlatformDialogHelper::DialogCode m_code; diff --git a/src/plugins/platforms/windows/qwindowsdialoghelpers.h b/src/plugins/platforms/windows/qwindowsdialoghelpers.h index b3101a1419..55f112c57a 100644 --- a/src/plugins/platforms/windows/qwindowsdialoghelpers.h +++ b/src/plugins/platforms/windows/qwindowsdialoghelpers.h @@ -69,19 +69,19 @@ public: typedef QSharedPointer<QWindowsNativeDialogBase> QWindowsNativeDialogBasePtr; ~QWindowsDialogHelperBase() { cleanupThread(); } - void exec() Q_DECL_OVERRIDE; + void exec() override; bool show(Qt::WindowFlags windowFlags, - Qt::WindowModality windowModality, - QWindow *parent) Q_DECL_OVERRIDE; - void hide() Q_DECL_OVERRIDE; + Qt::WindowModality windowModality, + QWindow *parent) override; + void hide() override; virtual bool supportsNonModalDialog(const QWindow * /* parent */ = 0) const { return true; } protected: - QWindowsDialogHelperBase(); + QWindowsDialogHelperBase() {} QWindowsNativeDialogBase *nativeDialog() const; inline bool hasNativeDialog() const { return m_nativeDialog; } - void timerEvent(QTimerEvent *) Q_DECL_OVERRIDE; + void timerEvent(QTimerEvent *) override; private: virtual QWindowsNativeDialogBase *createNativeDialog() = 0; @@ -91,9 +91,9 @@ private: void cleanupThread(); QWindowsNativeDialogBasePtr m_nativeDialog; - HWND m_ownerWindow; - int m_timerId; - QThread *m_thread; + HWND m_ownerWindow = 0; + int m_timerId = 0; + QThread *m_thread = nullptr; }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/windows/qwindowsdrag.cpp b/src/plugins/platforms/windows/qwindowsdrag.cpp index 26a5131927..58175b39fa 100644 --- a/src/plugins/platforms/windows/qwindowsdrag.cpp +++ b/src/plugins/platforms/windows/qwindowsdrag.cpp @@ -84,7 +84,7 @@ public: void setPixmap(const QPixmap &p); protected: - void paintEvent(QPaintEvent *) Q_DECL_OVERRIDE + void paintEvent(QPaintEvent *) override { QPainter painter(this); painter.drawPixmap(0, 0, m_pixmap); @@ -190,6 +190,20 @@ static inline Qt::KeyboardModifiers toQtKeyboardModifiers(DWORD keyState) return modifiers; } +static inline Qt::MouseButtons toQtMouseButtons(DWORD keyState) +{ + Qt::MouseButtons buttons = Qt::NoButton; + + if (keyState & MK_LBUTTON) + buttons |= Qt::LeftButton; + if (keyState & MK_RBUTTON) + buttons |= Qt::RightButton; + if (keyState & MK_MBUTTON) + buttons |= Qt::MidButton; + + return buttons; +} + /*! \class QWindowsOleDropSource \brief Implementation of IDropSource @@ -398,43 +412,39 @@ QWindowsOleDropSource::Release(void) QT_ENSURE_STACK_ALIGNED_FOR_SSE STDMETHODIMP QWindowsOleDropSource::QueryContinueDrag(BOOL fEscapePressed, DWORD grfKeyState) { - HRESULT hr = S_OK; - do { - if (fEscapePressed || QWindowsDrag::isCanceled()) { - hr = ResultFromScode(DRAGDROP_S_CANCEL); - break; - } - - // grfKeyState is broken on CE & some Windows XP versions, - // therefore we need to check the state manually - if ((GetAsyncKeyState(VK_LBUTTON) == 0) - && (GetAsyncKeyState(VK_MBUTTON) == 0) - && (GetAsyncKeyState(VK_RBUTTON) == 0)) { - hr = ResultFromScode(DRAGDROP_S_DROP); - break; - } + Qt::MouseButtons buttons = toQtMouseButtons(grfKeyState); - const Qt::MouseButtons buttons = QWindowsMouseHandler::keyStateToMouseButtons(grfKeyState); - if (m_currentButtons == Qt::NoButton) { - m_currentButtons = buttons; + SCODE result = S_OK; + if (fEscapePressed || QWindowsDrag::isCanceled()) { + result = DRAGDROP_S_CANCEL; + buttons = Qt::NoButton; } else { - // Button changed: Complete Drop operation. - if (!(m_currentButtons & buttons)) { - hr = ResultFromScode(DRAGDROP_S_DROP); - break; + if (buttons && !m_currentButtons) { + m_currentButtons = buttons; + } else if (!(m_currentButtons & buttons)) { // Button changed: Complete Drop operation. + result = DRAGDROP_S_DROP; } } - QGuiApplication::processEvents(); + switch (result) { + case DRAGDROP_S_DROP: + case DRAGDROP_S_CANCEL: + QGuiApplicationPrivate::modifier_buttons = toQtKeyboardModifiers(grfKeyState); + QGuiApplicationPrivate::mouse_buttons = buttons; + m_currentButtons = Qt::NoButton; + break; - } while (false); + default: + QGuiApplication::processEvents(); + break; + } - if (QWindowsContext::verbose > 1 || hr != S_OK) { + if (QWindowsContext::verbose > 1 || result != S_OK) { qCDebug(lcQpaMime) << __FUNCTION__ << "fEscapePressed=" << fEscapePressed << "grfKeyState=" << grfKeyState << "buttons" << m_currentButtons - << "returns 0x" << hex <<int(hr) << dec; + << "returns 0x" << hex << int(result) << dec; } - return hr; + return ResultFromScode(result); } /*! @@ -489,8 +499,7 @@ QWindowsOleDropSource::GiveFeedback(DWORD dwEffect) \ingroup qt-lighthouse-win */ -QWindowsOleDropTarget::QWindowsOleDropTarget(QWindow *w) : - m_refs(1), m_window(w), m_chosenEffect(0), m_lastKeyState(0) +QWindowsOleDropTarget::QWindowsOleDropTarget(QWindow *w) : m_window(w) { qCDebug(lcQpaMime) << __FUNCTION__ << this << w; } @@ -538,7 +547,7 @@ void QWindowsOleDropTarget::handleDrag(QWindow *window, DWORD grfKeyState, QWindowsDrag *windowsDrag = QWindowsDrag::instance(); const Qt::DropActions actions = translateToQDragDropActions(*pdwEffect); QGuiApplicationPrivate::modifier_buttons = toQtKeyboardModifiers(grfKeyState); - QGuiApplicationPrivate::mouse_buttons = QWindowsMouseHandler::keyStateToMouseButtons(grfKeyState); + QGuiApplicationPrivate::mouse_buttons = toQtMouseButtons(grfKeyState); const QPlatformDragQtResponse response = QWindowSystemInterface::handleDrag(window, windowsDrag->dropData(), m_lastPoint, actions); @@ -606,6 +615,12 @@ QWindowsOleDropTarget::DragLeave() qCDebug(lcQpaMime) << __FUNCTION__ << ' ' << m_window; QWindowSystemInterface::handleDrag(m_window, 0, QPoint(), Qt::IgnoreAction); + + if (!QDragManager::self()->source()) { + QGuiApplicationPrivate::modifier_buttons = Qt::NoModifier; + QGuiApplicationPrivate::mouse_buttons = Qt::NoButton; + m_lastKeyState = 0; + } QWindowsDrag::instance()->releaseDropDataObject(); return NOERROR; @@ -624,11 +639,9 @@ QWindowsOleDropTarget::Drop(LPDATAOBJECT pDataObj, DWORD grfKeyState, << "keys=" << grfKeyState << "pt=" << pt.x << ',' << pt.y; m_lastPoint = QWindowsGeometryHint::mapFromGlobal(m_window, QPoint(pt.x,pt.y)); - // grfKeyState does not all ways contain button state in the drop so if - // it doesn't then use the last known button state; - if ((grfKeyState & KEY_STATE_BUTTON_MASK) == 0) - grfKeyState |= m_lastKeyState & KEY_STATE_BUTTON_MASK; - m_lastKeyState = grfKeyState; + // grfKeyState does not all ways contain button state in the drop + QGuiApplicationPrivate::mouse_buttons = toQtMouseButtons(m_lastKeyState); + QGuiApplicationPrivate::modifier_buttons = toQtKeyboardModifiers(grfKeyState); QWindowsDrag *windowsDrag = QWindowsDrag::instance(); @@ -636,6 +649,10 @@ QWindowsOleDropTarget::Drop(LPDATAOBJECT pDataObj, DWORD grfKeyState, QWindowSystemInterface::handleDrop(m_window, windowsDrag->dropData(), m_lastPoint, translateToQDragDropActions(*pdwEffect)); + + QGuiApplicationPrivate::mouse_buttons = toQtMouseButtons(grfKeyState); + m_lastKeyState = grfKeyState; + if (response.isAccepted()) { const Qt::DropAction action = response.acceptedAction(); if (action == Qt::MoveAction || action == Qt::TargetMoveAction) { @@ -682,10 +699,7 @@ QWindowsOleDropTarget::Drop(LPDATAOBJECT pDataObj, DWORD grfKeyState, bool QWindowsDrag::m_canceled = false; -QWindowsDrag::QWindowsDrag() : - m_dropDataObject(0), m_cachedDropTargetHelper(0) -{ -} +QWindowsDrag::QWindowsDrag() = default; QWindowsDrag::~QWindowsDrag() { diff --git a/src/plugins/platforms/windows/qwindowsdrag.h b/src/plugins/platforms/windows/qwindowsdrag.h index e81bc7dc61..983f3a67b4 100644 --- a/src/plugins/platforms/windows/qwindowsdrag.h +++ b/src/plugins/platforms/windows/qwindowsdrag.h @@ -54,7 +54,7 @@ class QPlatformScreen; class QWindowsDropMimeData : public QWindowsInternalMimeData { public: QWindowsDropMimeData() {} - IDataObject *retrieveDataObject() const Q_DECL_OVERRIDE; + IDataObject *retrieveDataObject() const override; }; class QWindowsOleDropTarget : public IDropTarget @@ -77,12 +77,12 @@ public: private: void handleDrag(QWindow *window, DWORD grfKeyState, const QPoint &, LPDWORD pdwEffect); - ULONG m_refs; + ULONG m_refs = 1; QWindow *const m_window; QRect m_answerRect; QPoint m_lastPoint; - DWORD m_chosenEffect; - DWORD m_lastKeyState; + DWORD m_chosenEffect = 0; + DWORD m_lastKeyState = 0; }; class QWindowsDrag : public QPlatformDrag @@ -91,12 +91,12 @@ public: QWindowsDrag(); virtual ~QWindowsDrag(); - QMimeData *platformDropData() Q_DECL_OVERRIDE { return &m_dropData; } + QMimeData *platformDropData() override { return &m_dropData; } - Qt::DropAction drag(QDrag *drag) Q_DECL_OVERRIDE; + Qt::DropAction drag(QDrag *drag) override; static QWindowsDrag *instance(); - void cancelDrag() Q_DECL_OVERRIDE { QWindowsDrag::m_canceled = true; } + void cancelDrag() override { QWindowsDrag::m_canceled = true; } static bool isCanceled() { return QWindowsDrag::m_canceled; } IDataObject *dropDataObject() const { return m_dropDataObject; } @@ -110,9 +110,9 @@ private: static bool m_canceled; QWindowsDropMimeData m_dropData; - IDataObject *m_dropDataObject; + IDataObject *m_dropDataObject = nullptr; - IDropTargetHelper* m_cachedDropTargetHelper; + IDropTargetHelper* m_cachedDropTargetHelper = nullptr; }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/windows/qwindowseglcontext.cpp b/src/plugins/platforms/windows/qwindowseglcontext.cpp index a4738dc100..4632c9c157 100644 --- a/src/plugins/platforms/windows/qwindowseglcontext.cpp +++ b/src/plugins/platforms/windows/qwindowseglcontext.cpp @@ -384,8 +384,6 @@ QWindowsEGLContext::QWindowsEGLContext(QWindowsEGLStaticContext *staticContext, QPlatformOpenGLContext *share) : m_staticContext(staticContext) , m_eglDisplay(staticContext->display()) - , m_api(EGL_OPENGL_ES_API) - , m_swapInterval(-1) { if (!m_staticContext) return; diff --git a/src/plugins/platforms/windows/qwindowseglcontext.h b/src/plugins/platforms/windows/qwindowseglcontext.h index 48a19f81e5..47878a7169 100644 --- a/src/plugins/platforms/windows/qwindowseglcontext.h +++ b/src/plugins/platforms/windows/qwindowseglcontext.h @@ -117,12 +117,12 @@ public: EGLDisplay display() const { return m_display; } - QWindowsOpenGLContext *createContext(QOpenGLContext *context) Q_DECL_OVERRIDE; - void *moduleHandle() const Q_DECL_OVERRIDE { return libGLESv2.moduleHandle(); } - QOpenGLContext::OpenGLModuleType moduleType() const Q_DECL_OVERRIDE { return QOpenGLContext::LibGLES; } + QWindowsOpenGLContext *createContext(QOpenGLContext *context) override; + void *moduleHandle() const override { return libGLESv2.moduleHandle(); } + QOpenGLContext::OpenGLModuleType moduleType() const override { return QOpenGLContext::LibGLES; } - void *createWindowSurface(void *nativeWindow, void *nativeConfig, int *err) Q_DECL_OVERRIDE; - void destroyWindowSurface(void *nativeSurface) Q_DECL_OVERRIDE; + void *createWindowSurface(void *nativeWindow, void *nativeConfig, int *err) override; + void destroyWindowSurface(void *nativeSurface) override; QSurfaceFormat formatFromConfig(EGLDisplay display, EGLConfig config, const QSurfaceFormat &referenceFormat); @@ -145,18 +145,18 @@ public: QPlatformOpenGLContext *share); ~QWindowsEGLContext(); - bool makeCurrent(QPlatformSurface *surface) Q_DECL_OVERRIDE; - void doneCurrent() Q_DECL_OVERRIDE; - void swapBuffers(QPlatformSurface *surface) Q_DECL_OVERRIDE; - QFunctionPointer getProcAddress(const char *procName) Q_DECL_OVERRIDE; + bool makeCurrent(QPlatformSurface *surface) override; + void doneCurrent() override; + void swapBuffers(QPlatformSurface *surface) override; + QFunctionPointer getProcAddress(const char *procName) override; - QSurfaceFormat format() const Q_DECL_OVERRIDE { return m_format; } - bool isSharing() const Q_DECL_OVERRIDE { return m_shareContext != EGL_NO_CONTEXT; } - bool isValid() const Q_DECL_OVERRIDE { return m_eglContext != EGL_NO_CONTEXT; } + QSurfaceFormat format() const override { return m_format; } + bool isSharing() const override { return m_shareContext != EGL_NO_CONTEXT; } + bool isValid() const override { return m_eglContext != EGL_NO_CONTEXT; } - void *nativeContext() const Q_DECL_OVERRIDE { return m_eglContext; } - void *nativeDisplay() const Q_DECL_OVERRIDE { return m_eglDisplay; } - void *nativeConfig() const Q_DECL_OVERRIDE { return m_eglConfig; } + void *nativeContext() const override { return m_eglContext; } + void *nativeDisplay() const override { return m_eglDisplay; } + void *nativeConfig() const override { return m_eglConfig; } private: EGLConfig chooseConfig(const QSurfaceFormat &format); @@ -167,8 +167,8 @@ private: EGLDisplay m_eglDisplay; EGLConfig m_eglConfig; QSurfaceFormat m_format; - EGLenum m_api; - int m_swapInterval; + EGLenum m_api = EGL_OPENGL_ES_API; + int m_swapInterval = -1; }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/windows/qwindowsgdiintegration.h b/src/plugins/platforms/windows/qwindowsgdiintegration.h index 46af20a083..ec67a99bc9 100644 --- a/src/plugins/platforms/windows/qwindowsgdiintegration.h +++ b/src/plugins/platforms/windows/qwindowsgdiintegration.h @@ -51,9 +51,9 @@ public: explicit QWindowsGdiIntegration(const QStringList ¶mList); virtual ~QWindowsGdiIntegration(); - QPlatformNativeInterface *nativeInterface() const Q_DECL_OVERRIDE; - QPlatformPixmap *createPlatformPixmap(QPlatformPixmap::PixelType type) const Q_DECL_OVERRIDE; - QPlatformBackingStore *createPlatformBackingStore(QWindow *window) const Q_DECL_OVERRIDE; + QPlatformNativeInterface *nativeInterface() const override; + QPlatformPixmap *createPlatformPixmap(QPlatformPixmap::PixelType type) const override; + QPlatformBackingStore *createPlatformBackingStore(QWindow *window) const override; private: QScopedPointer<QWindowsGdiIntegrationPrivate> d; diff --git a/src/plugins/platforms/windows/qwindowsgdinativeinterface.h b/src/plugins/platforms/windows/qwindowsgdinativeinterface.h index f0464bc823..c86d3cbb47 100644 --- a/src/plugins/platforms/windows/qwindowsgdinativeinterface.h +++ b/src/plugins/platforms/windows/qwindowsgdinativeinterface.h @@ -48,7 +48,7 @@ class QWindowsGdiNativeInterface : public QWindowsNativeInterface { Q_OBJECT public: - void *nativeResourceForBackingStore(const QByteArray &resource, QBackingStore *bs) Q_DECL_OVERRIDE; + void *nativeResourceForBackingStore(const QByteArray &resource, QBackingStore *bs) override; }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/windows/qwindowsglcontext.cpp b/src/plugins/platforms/windows/qwindowsglcontext.cpp index c1eb664324..751807e897 100644 --- a/src/plugins/platforms/windows/qwindowsglcontext.cpp +++ b/src/plugins/platforms/windows/qwindowsglcontext.cpp @@ -825,13 +825,6 @@ static inline QOpenGLContextData createDummyWindowOpenGLContextData() \ingroup qt-lighthouse-win */ -QWindowsOpenGLContextFormat::QWindowsOpenGLContextFormat() : - profile(QSurfaceFormat::NoProfile), - version(0), - options(0) -{ -} - QWindowsOpenGLContextFormat QWindowsOpenGLContextFormat::current() { QWindowsOpenGLContextFormat result; diff --git a/src/plugins/platforms/windows/qwindowsglcontext.h b/src/plugins/platforms/windows/qwindowsglcontext.h index 048b22bbf7..dfaa428520 100644 --- a/src/plugins/platforms/windows/qwindowsglcontext.h +++ b/src/plugins/platforms/windows/qwindowsglcontext.h @@ -73,24 +73,23 @@ struct QWindowsOpenGLAdditionalFormat struct QOpenGLContextData { QOpenGLContextData(HGLRC r, HWND h, HDC d) : renderingContext(r), hwnd(h), hdc(d) {} - QOpenGLContextData() : renderingContext(0), hwnd(0), hdc(0) {} + QOpenGLContextData() {} - HGLRC renderingContext; - HWND hwnd; - HDC hdc; + HGLRC renderingContext = 0; + HWND hwnd = 0; + HDC hdc = 0; }; class QOpenGLStaticContext; struct QWindowsOpenGLContextFormat { - QWindowsOpenGLContextFormat(); static QWindowsOpenGLContextFormat current(); void apply(QSurfaceFormat *format) const; - QSurfaceFormat::OpenGLContextProfile profile; - int version; //! majorVersion<<8 + minorVersion - QSurfaceFormat::FormatOptions options; + QSurfaceFormat::OpenGLContextProfile profile = QSurfaceFormat::NoProfile; + int version = 0; //! majorVersion<<8 + minorVersion + QSurfaceFormat::FormatOptions options = 0; }; #ifndef QT_NO_DEBUG_STREAM @@ -195,22 +194,22 @@ class QWindowsGLContext : public QWindowsOpenGLContext public: explicit QWindowsGLContext(QOpenGLStaticContext *staticContext, QOpenGLContext *context); ~QWindowsGLContext(); - bool isSharing() const Q_DECL_OVERRIDE { return m_context->shareHandle(); } - bool isValid() const Q_DECL_OVERRIDE { return m_renderingContext && !m_lost; } - QSurfaceFormat format() const Q_DECL_OVERRIDE { return m_obtainedFormat; } + bool isSharing() const override { return m_context->shareHandle(); } + bool isValid() const override { return m_renderingContext && !m_lost; } + QSurfaceFormat format() const override { return m_obtainedFormat; } - void swapBuffers(QPlatformSurface *surface) Q_DECL_OVERRIDE; + void swapBuffers(QPlatformSurface *surface) override; - bool makeCurrent(QPlatformSurface *surface) Q_DECL_OVERRIDE; - void doneCurrent() Q_DECL_OVERRIDE; + bool makeCurrent(QPlatformSurface *surface) override; + void doneCurrent() override; typedef void (*GL_Proc) (); - QFunctionPointer getProcAddress(const char *procName) Q_DECL_OVERRIDE; + QFunctionPointer getProcAddress(const char *procName) override; HGLRC renderingContext() const { return m_renderingContext; } - void *nativeContext() const Q_DECL_OVERRIDE { return m_renderingContext; } + void *nativeContext() const override { return m_renderingContext; } private: inline void releaseDCs(); diff --git a/src/plugins/platforms/windows/qwindowsinputcontext.cpp b/src/plugins/platforms/windows/qwindowsinputcontext.cpp index 8adbd494c4..e7ebf73d5d 100644 --- a/src/plugins/platforms/windows/qwindowsinputcontext.cpp +++ b/src/plugins/platforms/windows/qwindowsinputcontext.cpp @@ -166,15 +166,8 @@ Q_CORE_EXPORT QLocale qt_localeFromLCID(LCID id); // from qlocale_win.cpp HIMC QWindowsInputContext::m_defaultContext = 0; -QWindowsInputContext::CompositionContext::CompositionContext() : - hwnd(0), haveCaret(false), position(0), isComposing(false), - factor(1) -{ -} - QWindowsInputContext::QWindowsInputContext() : m_WM_MSIME_MOUSE(RegisterWindowMessage(L"MSIMEMouseOperation")), - m_endCompositionRecursionGuard(false), m_languageId(currentInputLanguageId()), m_locale(qt_localeFromLCID(m_languageId)) { diff --git a/src/plugins/platforms/windows/qwindowsinputcontext.h b/src/plugins/platforms/windows/qwindowsinputcontext.h index a7fa2c4f94..617ef30cef 100644 --- a/src/plugins/platforms/windows/qwindowsinputcontext.h +++ b/src/plugins/platforms/windows/qwindowsinputcontext.h @@ -57,15 +57,13 @@ class QWindowsInputContext : public QPlatformInputContext struct CompositionContext { - CompositionContext(); - - HWND hwnd; - bool haveCaret; + HWND hwnd = 0; + bool haveCaret = false; QString composition; - int position; - bool isComposing; + int position = 0; + bool isComposing = false; QPointer<QObject> focusObject; - qreal factor; + qreal factor = 1; }; public: explicit QWindowsInputContext(); @@ -73,13 +71,13 @@ public: static void setWindowsImeEnabled(QWindowsWindow *platformWindow, bool enabled); - bool hasCapability(Capability capability) const Q_DECL_OVERRIDE; - QLocale locale() const Q_DECL_OVERRIDE { return m_locale; } + bool hasCapability(Capability capability) const override; + QLocale locale() const override { return m_locale; } - void reset() Q_DECL_OVERRIDE; - void update(Qt::InputMethodQueries) Q_DECL_OVERRIDE; - void invokeAction(QInputMethod::Action, int cursorPosition) Q_DECL_OVERRIDE; - void setFocusObject(QObject *object) Q_DECL_OVERRIDE; + void reset() override; + void update(Qt::InputMethodQueries) override; + void invokeAction(QInputMethod::Action, int cursorPosition) override; + void setFocusObject(QObject *object) override; bool startComposition(HWND hwnd); bool composition(HWND hwnd, LPARAM lParam); @@ -104,7 +102,7 @@ private: const DWORD m_WM_MSIME_MOUSE; static HIMC m_defaultContext; CompositionContext m_compositionContext; - bool m_endCompositionRecursionGuard; + bool m_endCompositionRecursionGuard = false; LCID m_languageId; QLocale m_locale; }; diff --git a/src/plugins/platforms/windows/qwindowsintegration.cpp b/src/plugins/platforms/windows/qwindowsintegration.cpp index 3f74fd5296..316f93e3ac 100644 --- a/src/plugins/platforms/windows/qwindowsintegration.cpp +++ b/src/plugins/platforms/windows/qwindowsintegration.cpp @@ -129,9 +129,9 @@ struct QWindowsIntegrationPrivate explicit QWindowsIntegrationPrivate(const QStringList ¶mList); ~QWindowsIntegrationPrivate(); - unsigned m_options; + unsigned m_options = 0; QWindowsContext m_context; - QPlatformFontDatabase *m_fontDatabase; + QPlatformFontDatabase *m_fontDatabase = nullptr; #ifndef QT_NO_CLIPBOARD QWindowsClipboard m_clipboard; # ifndef QT_NO_DRAGANDDROP @@ -209,8 +209,6 @@ static inline unsigned parseOptions(const QStringList ¶mList, } QWindowsIntegrationPrivate::QWindowsIntegrationPrivate(const QStringList ¶mList) - : m_options(0) - , m_fontDatabase(0) { Q_INIT_RESOURCE(openglblacklists); @@ -306,24 +304,6 @@ QPlatformWindow *QWindowsIntegration::createPlatformWindow(QWindow *window) cons return result; } - if (window->type() == Qt::ForeignWindow) { - const HWND hwnd = reinterpret_cast<HWND>(window->winId()); - if (!IsWindow(hwnd)) { - qWarning("Windows QPA: Invalid foreign window ID %p.", hwnd); - return nullptr; - } - QWindowsForeignWindow *result = new QWindowsForeignWindow(window, hwnd); - const QRect obtainedGeometry = result->geometry(); - QScreen *screen = Q_NULLPTR; - if (const QPlatformScreen *pScreen = result->screenForGeometry(obtainedGeometry)) - screen = pScreen->screen(); - if (screen && screen != window->screen()) - window->setScreen(screen); - qCDebug(lcQpaWindows) << "Foreign window:" << window << showbase << hex - << result->winId() << noshowbase << dec << obtainedGeometry << screen; - return result; - } - QWindowsWindowData requested; requested.flags = window->flags(); requested.geometry = QHighDpi::toNativePixels(window->geometry(), window); @@ -367,6 +347,25 @@ QPlatformWindow *QWindowsIntegration::createPlatformWindow(QWindow *window) cons return result; } +QPlatformWindow *QWindowsIntegration::createForeignWindow(QWindow *window, WId nativeHandle) const +{ + const HWND hwnd = reinterpret_cast<HWND>(nativeHandle); + if (!IsWindow(hwnd)) { + qWarning("Windows QPA: Invalid foreign window ID %p.", hwnd); + return nullptr; + } + QWindowsForeignWindow *result = new QWindowsForeignWindow(window, hwnd); + const QRect obtainedGeometry = result->geometry(); + QScreen *screen = Q_NULLPTR; + if (const QPlatformScreen *pScreen = result->screenForGeometry(obtainedGeometry)) + screen = pScreen->screen(); + if (screen && screen != window->screen()) + window->setScreen(screen); + qCDebug(lcQpaWindows) << "Foreign window:" << window << showbase << hex + << result->winId() << noshowbase << dec << obtainedGeometry << screen; + return result; +} + // Overridden to return a QWindowsDirect2DWindow in Direct2D plugin. QWindowsWindow *QWindowsIntegration::createPlatformWindowHelper(QWindow *window, const QWindowsWindowData &data) const { diff --git a/src/plugins/platforms/windows/qwindowsintegration.h b/src/plugins/platforms/windows/qwindowsintegration.h index a668470993..607203829f 100644 --- a/src/plugins/platforms/windows/qwindowsintegration.h +++ b/src/plugins/platforms/windows/qwindowsintegration.h @@ -70,34 +70,35 @@ public: explicit QWindowsIntegration(const QStringList ¶mList); virtual ~QWindowsIntegration(); - bool hasCapability(QPlatformIntegration::Capability cap) const Q_DECL_OVERRIDE; + bool hasCapability(QPlatformIntegration::Capability cap) const override; - QPlatformWindow *createPlatformWindow(QWindow *window) const Q_DECL_OVERRIDE; + QPlatformWindow *createPlatformWindow(QWindow *window) const override; + QPlatformWindow *createForeignWindow(QWindow *window, WId nativeHandle) const override; #ifndef QT_NO_OPENGL - QPlatformOpenGLContext *createPlatformOpenGLContext(QOpenGLContext *context) const Q_DECL_OVERRIDE; - QOpenGLContext::OpenGLModuleType openGLModuleType() Q_DECL_OVERRIDE; + QPlatformOpenGLContext *createPlatformOpenGLContext(QOpenGLContext *context) const override; + QOpenGLContext::OpenGLModuleType openGLModuleType() override; static QWindowsStaticOpenGLContext *staticOpenGLContext(); #endif - QAbstractEventDispatcher *createEventDispatcher() const Q_DECL_OVERRIDE; - void initialize() Q_DECL_OVERRIDE; + QAbstractEventDispatcher *createEventDispatcher() const override; + void initialize() override; #ifndef QT_NO_CLIPBOARD - QPlatformClipboard *clipboard() const Q_DECL_OVERRIDE; + QPlatformClipboard *clipboard() const override; # ifndef QT_NO_DRAGANDDROP - QPlatformDrag *drag() const Q_DECL_OVERRIDE; + QPlatformDrag *drag() const override; # endif #endif // !QT_NO_CLIPBOARD - QPlatformInputContext *inputContext() const Q_DECL_OVERRIDE; + QPlatformInputContext *inputContext() const override; #ifndef QT_NO_ACCESSIBILITY - QPlatformAccessibility *accessibility() const Q_DECL_OVERRIDE; + QPlatformAccessibility *accessibility() const override; #endif - QPlatformFontDatabase *fontDatabase() const Q_DECL_OVERRIDE; - QStringList themeNames() const Q_DECL_OVERRIDE; - QPlatformTheme *createPlatformTheme(const QString &name) const Q_DECL_OVERRIDE; - QPlatformServices *services() const Q_DECL_OVERRIDE; - QVariant styleHint(StyleHint hint) const Q_DECL_OVERRIDE; + QPlatformFontDatabase *fontDatabase() const override; + QStringList themeNames() const override; + QPlatformTheme *createPlatformTheme(const QString &name) const override; + QPlatformServices *services() const override; + QVariant styleHint(StyleHint hint) const override; - Qt::KeyboardModifiers queryKeyboardModifiers() const Q_DECL_OVERRIDE; - QList<int> possibleKeys(const QKeyEvent *e) const Q_DECL_OVERRIDE; + Qt::KeyboardModifiers queryKeyboardModifiers() const override; + QList<int> possibleKeys(const QKeyEvent *e) const override; static QWindowsIntegration *instance() { return m_instance; } @@ -106,10 +107,10 @@ public: unsigned options() const; - void beep() const Q_DECL_OVERRIDE; + void beep() const override; #if !defined(QT_NO_SESSIONMANAGER) - QPlatformSessionManager *createPlatformSessionManager(const QString &id, const QString &key) const Q_DECL_OVERRIDE; + QPlatformSessionManager *createPlatformSessionManager(const QString &id, const QString &key) const override; #endif protected: diff --git a/src/plugins/platforms/windows/qwindowsinternalmimedata.h b/src/plugins/platforms/windows/qwindowsinternalmimedata.h index 4d775b1f21..a7df1ee6e0 100644 --- a/src/plugins/platforms/windows/qwindowsinternalmimedata.h +++ b/src/plugins/platforms/windows/qwindowsinternalmimedata.h @@ -52,9 +52,9 @@ class QDebug; // Implementation in qwindowsclipboard.cpp. class QWindowsInternalMimeData : public QInternalMimeData { public: - bool hasFormat_sys(const QString &mimetype) const Q_DECL_OVERRIDE; - QStringList formats_sys() const Q_DECL_OVERRIDE; - QVariant retrieveData_sys(const QString &mimetype, QVariant::Type preferredType) const Q_DECL_OVERRIDE; + bool hasFormat_sys(const QString &mimetype) const override; + QStringList formats_sys() const override; + QVariant retrieveData_sys(const QString &mimetype, QVariant::Type preferredType) const override; protected: virtual IDataObject *retrieveDataObject() const = 0; diff --git a/src/plugins/platforms/windows/qwindowskeymapper.cpp b/src/plugins/platforms/windows/qwindowskeymapper.cpp index b84b586f7c..24c2df86d4 100644 --- a/src/plugins/platforms/windows/qwindowskeymapper.cpp +++ b/src/plugins/platforms/windows/qwindowskeymapper.cpp @@ -144,13 +144,11 @@ struct KeyRecord { static const int QT_MAX_KEY_RECORDINGS = 64; // User has LOTS of fingers... struct KeyRecorder { - KeyRecorder() : nrecs(0) {} - inline KeyRecord *findKey(int code, bool remove); inline void storeKey(int code, int ascii, int state, const QString& text); inline void clearKeys(); - int nrecs; + int nrecs = 0; KeyRecord deleted_record; // A copy of last entry removed from records[] KeyRecord records[QT_MAX_KEY_RECORDINGS]; }; @@ -973,7 +971,8 @@ bool QWindowsKeyMapper::translateKeyEventInternal(QWindow *window, const MSG &ms state = state ^ Qt::ShiftModifier; else if (code == Qt::Key_Alt) state = state ^ Qt::AltModifier; - + else if (code == 0 && modifiersIndex != 0) + code = keyLayout[vk_key].qtKey[0]; // If the bit 24 of lParm is set you received a enter, // otherwise a Return. (This is the extended key bit) if ((code == Qt::Key_Return) && (msg.lParam & 0x1000000)) diff --git a/src/plugins/platforms/windows/qwindowsmime.cpp b/src/plugins/platforms/windows/qwindowsmime.cpp index 30d438a127..71fd12d71b 100644 --- a/src/plugins/platforms/windows/qwindowsmime.cpp +++ b/src/plugins/platforms/windows/qwindowsmime.cpp @@ -893,14 +893,14 @@ public: QWindowsMimeHtml(); // for converting from Qt - bool canConvertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData) const Q_DECL_OVERRIDE; - bool convertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData, STGMEDIUM * pmedium) const Q_DECL_OVERRIDE; - QVector<FORMATETC> formatsForMime(const QString &mimeType, const QMimeData *mimeData) const Q_DECL_OVERRIDE; + bool canConvertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData) const override; + bool convertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData, STGMEDIUM * pmedium) const override; + QVector<FORMATETC> formatsForMime(const QString &mimeType, const QMimeData *mimeData) const override; // for converting to Qt - bool canConvertToMime(const QString &mimeType, IDataObject *pDataObj) const Q_DECL_OVERRIDE; - QVariant convertToMime(const QString &mime, IDataObject *pDataObj, QVariant::Type preferredType) const Q_DECL_OVERRIDE; - QString mimeForFormat(const FORMATETC &formatetc) const Q_DECL_OVERRIDE; + bool canConvertToMime(const QString &mimeType, IDataObject *pDataObj) const override; + QVariant convertToMime(const QString &mime, IDataObject *pDataObj, QVariant::Type preferredType) const override; + QString mimeForFormat(const FORMATETC &formatetc) const override; private: int CF_HTML; @@ -1025,14 +1025,14 @@ class QWindowsMimeImage : public QWindowsMime public: QWindowsMimeImage(); // for converting from Qt - bool canConvertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData) const Q_DECL_OVERRIDE; - bool convertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData, STGMEDIUM * pmedium) const Q_DECL_OVERRIDE; - QVector<FORMATETC> formatsForMime(const QString &mimeType, const QMimeData *mimeData) const Q_DECL_OVERRIDE; + bool canConvertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData) const override; + bool convertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData, STGMEDIUM * pmedium) const override; + QVector<FORMATETC> formatsForMime(const QString &mimeType, const QMimeData *mimeData) const override; // for converting to Qt - bool canConvertToMime(const QString &mimeType, IDataObject *pDataObj) const Q_DECL_OVERRIDE; - QVariant convertToMime(const QString &mime, IDataObject *pDataObj, QVariant::Type preferredType) const Q_DECL_OVERRIDE; - QString mimeForFormat(const FORMATETC &formatetc) const Q_DECL_OVERRIDE; + bool canConvertToMime(const QString &mimeType, IDataObject *pDataObj) const override; + QVariant convertToMime(const QString &mime, IDataObject *pDataObj, QVariant::Type preferredType) const override; + QString mimeForFormat(const FORMATETC &formatetc) const override; private: bool hasOriginalDIBV5(IDataObject *pDataObj) const; UINT CF_PNG; @@ -1179,14 +1179,14 @@ public: QBuiltInMimes(); // for converting from Qt - bool canConvertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData) const Q_DECL_OVERRIDE; - bool convertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData, STGMEDIUM * pmedium) const Q_DECL_OVERRIDE; - QVector<FORMATETC> formatsForMime(const QString &mimeType, const QMimeData *mimeData) const Q_DECL_OVERRIDE; + bool canConvertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData) const override; + bool convertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData, STGMEDIUM * pmedium) const override; + QVector<FORMATETC> formatsForMime(const QString &mimeType, const QMimeData *mimeData) const override; // for converting to Qt - bool canConvertToMime(const QString &mimeType, IDataObject *pDataObj) const Q_DECL_OVERRIDE; - QVariant convertToMime(const QString &mime, IDataObject *pDataObj, QVariant::Type preferredType) const Q_DECL_OVERRIDE; - QString mimeForFormat(const FORMATETC &formatetc) const Q_DECL_OVERRIDE; + bool canConvertToMime(const QString &mimeType, IDataObject *pDataObj) const override; + QVariant convertToMime(const QString &mime, IDataObject *pDataObj, QVariant::Type preferredType) const override; + QString mimeForFormat(const FORMATETC &formatetc) const override; private: QMap<int, QString> outFormats; @@ -1299,14 +1299,14 @@ public: QLastResortMimes(); // for converting from Qt - bool canConvertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData) const Q_DECL_OVERRIDE; - bool convertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData, STGMEDIUM * pmedium) const Q_DECL_OVERRIDE; - QVector<FORMATETC> formatsForMime(const QString &mimeType, const QMimeData *mimeData) const Q_DECL_OVERRIDE; + bool canConvertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData) const override; + bool convertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData, STGMEDIUM * pmedium) const override; + QVector<FORMATETC> formatsForMime(const QString &mimeType, const QMimeData *mimeData) const override; // for converting to Qt - bool canConvertToMime(const QString &mimeType, IDataObject *pDataObj) const Q_DECL_OVERRIDE; - QVariant convertToMime(const QString &mime, IDataObject *pDataObj, QVariant::Type preferredType) const Q_DECL_OVERRIDE; - QString mimeForFormat(const FORMATETC &formatetc) const Q_DECL_OVERRIDE; + bool canConvertToMime(const QString &mimeType, IDataObject *pDataObj) const override; + QVariant convertToMime(const QString &mime, IDataObject *pDataObj, QVariant::Type preferredType) const override; + QString mimeForFormat(const FORMATETC &formatetc) const override; private: QMap<int, QString> formats; @@ -1496,9 +1496,7 @@ QString QLastResortMimes::mimeForFormat(const FORMATETC &formatetc) const \sa QWindowsMime */ -QWindowsMimeConverter::QWindowsMimeConverter() : m_internalMimeCount(0) -{ -} +QWindowsMimeConverter::QWindowsMimeConverter() = default; QWindowsMimeConverter::~QWindowsMimeConverter() { diff --git a/src/plugins/platforms/windows/qwindowsmime.h b/src/plugins/platforms/windows/qwindowsmime.h index 4c0cbf9f31..1ed2aa933f 100644 --- a/src/plugins/platforms/windows/qwindowsmime.h +++ b/src/plugins/platforms/windows/qwindowsmime.h @@ -96,7 +96,7 @@ private: void ensureInitialized() const; mutable QList<QWindowsMime *> m_mimes; - mutable int m_internalMimeCount; + mutable int m_internalMimeCount = 0; }; #ifndef QT_NO_DEBUG_STREAM diff --git a/src/plugins/platforms/windows/qwindowsmousehandler.cpp b/src/plugins/platforms/windows/qwindowsmousehandler.cpp index e4025fe60d..34c34fd28e 100644 --- a/src/plugins/platforms/windows/qwindowsmousehandler.cpp +++ b/src/plugins/platforms/windows/qwindowsmousehandler.cpp @@ -185,14 +185,7 @@ static inline QTouchDevice *createTouchDevice() \ingroup qt-lighthouse-win */ -QWindowsMouseHandler::QWindowsMouseHandler() : - m_windowUnderMouse(0), - m_trackedWindow(0), - m_touchDevice(Q_NULLPTR), - m_leftButtonDown(false), - m_previousCaptureWindow(0) -{ -} +QWindowsMouseHandler::QWindowsMouseHandler() = default; QTouchDevice *QWindowsMouseHandler::ensureTouchDevice() { @@ -421,7 +414,7 @@ static bool isValidWheelReceiver(QWindow *candidate) { if (candidate) { const QWindow *toplevel = QWindowsWindow::topLevelOf(candidate); - if (toplevel->type() == Qt::ForeignWindow) + if (toplevel->handle() && toplevel->handle()->isForeignWindow()) return true; if (const QWindowsWindow *ww = QWindowsWindow::windowsWindowOf(toplevel)) return !ww->testFlag(QWindowsWindow::BlockedByModal); diff --git a/src/plugins/platforms/windows/qwindowsmousehandler.h b/src/plugins/platforms/windows/qwindowsmousehandler.h index bd36d9f44c..86f18a0482 100644 --- a/src/plugins/platforms/windows/qwindowsmousehandler.h +++ b/src/plugins/platforms/windows/qwindowsmousehandler.h @@ -88,9 +88,9 @@ private: QPointer<QWindow> m_trackedWindow; QHash<DWORD, int> m_touchInputIDToTouchPointID; QHash<int, QPointF> m_lastTouchPositions; - QTouchDevice *m_touchDevice; - bool m_leftButtonDown; - QWindow *m_previousCaptureWindow; + QTouchDevice *m_touchDevice = nullptr; + bool m_leftButtonDown = false; + QWindow *m_previousCaptureWindow = nullptr; }; Qt::MouseButtons QWindowsMouseHandler::keyStateToMouseButtons(int wParam) diff --git a/src/plugins/platforms/windows/qwindowsnativeinterface.cpp b/src/plugins/platforms/windows/qwindowsnativeinterface.cpp index eaa6e45b9f..d750eef19d 100644 --- a/src/plugins/platforms/windows/qwindowsnativeinterface.cpp +++ b/src/plugins/platforms/windows/qwindowsnativeinterface.cpp @@ -38,6 +38,7 @@ ****************************************************************************/ #include "qwindowsnativeinterface.h" +#include "qwindowsclipboard.h" #include "qwindowswindow.h" #include "qwindowscontext.h" #include "qwindowscursor.h" @@ -45,6 +46,7 @@ #include "qwindowsopengltester.h" #include "qwindowsintegration.h" #include "qwindowsmime.h" +#include "qwin10helpers.h" #include <QtGui/QWindow> #include <QtGui/QOpenGLContext> @@ -108,6 +110,7 @@ void *QWindowsNativeInterface::nativeResourceForWindow(const QByteArray &resourc } break; case QWindow::OpenGLSurface: + case QWindow::OpenVGSurface: break; } qWarning("%s: Invalid key '%s' requested.", __FUNCTION__, resource.constData()); @@ -252,14 +255,23 @@ QFont QWindowsNativeInterface::logFontToQFont(const void *logFont, int verticalD return QWindowsFontDatabase::LOGFONT_to_QFont(*reinterpret_cast<const LOGFONT *>(logFont), verticalDpi); } +bool QWindowsNativeInterface::isTabletMode() +{ +#if QT_CONFIG(clipboard) + if (const QWindowsClipboard *clipboard = QWindowsClipboard::instance()) + return qt_windowsIsTabletMode(clipboard->clipboardViewer()); +#endif + return false; +} + QFunctionPointer QWindowsNativeInterface::platformFunction(const QByteArray &function) const { if (function == QWindowsWindowFunctions::setTouchWindowTouchTypeIdentifier()) return QFunctionPointer(QWindowsWindow::setTouchWindowTouchTypeStatic); else if (function == QWindowsWindowFunctions::setHasBorderInFullScreenIdentifier()) return QFunctionPointer(QWindowsWindow::setHasBorderInFullScreenStatic); - else if (function == QWindowsWindowFunctions::setWindowActivationBehaviorIdentifier()) - return QFunctionPointer(QWindowsNativeInterface::setWindowActivationBehavior); + else if (function == QWindowsWindowFunctions::isTabletModeIdentifier()) + return QFunctionPointer(QWindowsNativeInterface::isTabletMode); return Q_NULLPTR; } diff --git a/src/plugins/platforms/windows/qwindowsnativeinterface.h b/src/plugins/platforms/windows/qwindowsnativeinterface.h index 9fc43ddcce..d085a4afb3 100644 --- a/src/plugins/platforms/windows/qwindowsnativeinterface.h +++ b/src/plugins/platforms/windows/qwindowsnativeinterface.h @@ -68,13 +68,13 @@ class QWindowsNativeInterface : public QPlatformNativeInterface Q_PROPERTY(QVariant gpu READ gpu STORED false) public: - void *nativeResourceForIntegration(const QByteArray &resource) Q_DECL_OVERRIDE; + void *nativeResourceForIntegration(const QByteArray &resource) override; #ifndef QT_NO_OPENGL - void *nativeResourceForContext(const QByteArray &resource, QOpenGLContext *context) Q_DECL_OVERRIDE; + void *nativeResourceForContext(const QByteArray &resource, QOpenGLContext *context) override; #endif - void *nativeResourceForWindow(const QByteArray &resource, QWindow *window) Q_DECL_OVERRIDE; + void *nativeResourceForWindow(const QByteArray &resource, QWindow *window) override; #ifndef QT_NO_CURSOR - void *nativeResourceForCursor(const QByteArray &resource, const QCursor &cursor) Q_DECL_OVERRIDE; + void *nativeResourceForCursor(const QByteArray &resource, const QCursor &cursor) override; #endif Q_INVOKABLE void *createMessageWindow(const QString &classNameTemplate, const QString &windowName, @@ -92,17 +92,19 @@ public: QVariant gpu() const; - QVariantMap windowProperties(QPlatformWindow *window) const Q_DECL_OVERRIDE; - QVariant windowProperty(QPlatformWindow *window, const QString &name) const Q_DECL_OVERRIDE; - QVariant windowProperty(QPlatformWindow *window, const QString &name, const QVariant &defaultValue) const Q_DECL_OVERRIDE; - void setWindowProperty(QPlatformWindow *window, const QString &name, const QVariant &value) Q_DECL_OVERRIDE; + QVariantMap windowProperties(QPlatformWindow *window) const override; + QVariant windowProperty(QPlatformWindow *window, const QString &name) const override; + QVariant windowProperty(QPlatformWindow *window, const QString &name, const QVariant &defaultValue) const override; + void setWindowProperty(QPlatformWindow *window, const QString &name, const QVariant &value) override; static QWindowsWindowFunctions::WindowActivationBehavior windowActivationBehavior() { return QWindowsNativeInterface::m_windowActivationBehavior; } static void setWindowActivationBehavior(QWindowsWindowFunctions::WindowActivationBehavior b) { QWindowsNativeInterface::m_windowActivationBehavior = b; } - QFunctionPointer platformFunction(const QByteArray &function) const Q_DECL_OVERRIDE; + static bool isTabletMode(); + + QFunctionPointer platformFunction(const QByteArray &function) const override; private: static QWindowsWindowFunctions::WindowActivationBehavior m_windowActivationBehavior; diff --git a/src/plugins/platforms/windows/qwindowsole.cpp b/src/plugins/platforms/windows/qwindowsole.cpp index a1a8c0b499..9b71061aa5 100644 --- a/src/plugins/platforms/windows/qwindowsole.cpp +++ b/src/plugins/platforms/windows/qwindowsole.cpp @@ -74,9 +74,8 @@ QT_BEGIN_NAMESPACE */ QWindowsOleDataObject::QWindowsOleDataObject(QMimeData *mimeData) : - m_refs(1), data(mimeData), - CF_PERFORMEDDROPEFFECT(RegisterClipboardFormat(CFSTR_PERFORMEDDROPEFFECT)), - performedEffect(DROPEFFECT_NONE) + data(mimeData), + CF_PERFORMEDDROPEFFECT(RegisterClipboardFormat(CFSTR_PERFORMEDDROPEFFECT)) { qCDebug(lcQpaMime) << __FUNCTION__ << mimeData->formats(); } @@ -267,8 +266,7 @@ QWindowsOleDataObject::EnumDAdvise(LPENUMSTATDATA FAR*) \ingroup qt-lighthouse-win */ -QWindowsOleEnumFmtEtc::QWindowsOleEnumFmtEtc(const QVector<FORMATETC> &fmtetcs) : - m_dwRefs(1), m_nIndex(0), m_isNull(false) +QWindowsOleEnumFmtEtc::QWindowsOleEnumFmtEtc(const QVector<FORMATETC> &fmtetcs) { if (QWindowsContext::verbose > 1) qCDebug(lcQpaMime) << __FUNCTION__ << fmtetcs; @@ -285,8 +283,7 @@ QWindowsOleEnumFmtEtc::QWindowsOleEnumFmtEtc(const QVector<FORMATETC> &fmtetcs) } } -QWindowsOleEnumFmtEtc::QWindowsOleEnumFmtEtc(const QVector<LPFORMATETC> &lpfmtetcs) : - m_dwRefs(1), m_nIndex(0), m_isNull(false) +QWindowsOleEnumFmtEtc::QWindowsOleEnumFmtEtc(const QVector<LPFORMATETC> &lpfmtetcs) { if (QWindowsContext::verbose > 1) qCDebug(lcQpaMime) << __FUNCTION__; diff --git a/src/plugins/platforms/windows/qwindowsole.h b/src/plugins/platforms/windows/qwindowsole.h index dc31c793e9..643011272b 100644 --- a/src/plugins/platforms/windows/qwindowsole.h +++ b/src/plugins/platforms/windows/qwindowsole.h @@ -82,10 +82,10 @@ public: STDMETHOD(EnumDAdvise)(LPENUMSTATDATA FAR* ppenumAdvise); private: - ULONG m_refs; + ULONG m_refs = 1; QPointer<QMimeData> data; - int CF_PERFORMEDDROPEFFECT; - DWORD performedEffect; + const int CF_PERFORMEDDROPEFFECT; + DWORD performedEffect = DROPEFFECT_NONE; }; class QWindowsOleEnumFmtEtc : public IEnumFORMATETC @@ -111,10 +111,10 @@ public: private: bool copyFormatEtc(LPFORMATETC dest, const FORMATETC *src) const; - ULONG m_dwRefs; - ULONG m_nIndex; + ULONG m_dwRefs = 1; + ULONG m_nIndex = 0; QVector<LPFORMATETC> m_lpfmtetcs; - bool m_isNull; + bool m_isNull = false; }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/windows/qwindowsopengltester.h b/src/plugins/platforms/windows/qwindowsopengltester.h index 39e20b55d1..e3fec59dd5 100644 --- a/src/plugins/platforms/windows/qwindowsopengltester.h +++ b/src/plugins/platforms/windows/qwindowsopengltester.h @@ -51,16 +51,14 @@ class QVariant; struct GpuDescription { - GpuDescription() : vendorId(0), deviceId(0), revision(0), subSysId(0) {} - static GpuDescription detect(); QString toString() const; QVariant toVariant() const; - uint vendorId; - uint deviceId; - uint revision; - uint subSysId; + uint vendorId = 0; + uint deviceId = 0; + uint revision = 0; + uint subSysId = 0; QVersionNumber driverVersion; QByteArray driverName; QByteArray description; diff --git a/src/plugins/platforms/windows/qwindowsscreen.cpp b/src/plugins/platforms/windows/qwindowsscreen.cpp index c70323c06f..24fb12d27a 100644 --- a/src/plugins/platforms/windows/qwindowsscreen.cpp +++ b/src/plugins/platforms/windows/qwindowsscreen.cpp @@ -56,13 +56,6 @@ QT_BEGIN_NAMESPACE -QWindowsScreenData::QWindowsScreenData() : - dpi(96, 96), depth(32), format(QImage::Format_ARGB32_Premultiplied), - flags(VirtualDesktop), orientation(Qt::LandscapeOrientation), - refreshRateHz(60) -{ -} - static inline QDpi deviceDPI(HDC hdc) { return QDpi(GetDeviceCaps(hdc, LOGPIXELSX), GetDeviceCaps(hdc, LOGPIXELSY)); @@ -89,6 +82,7 @@ static bool monitorData(HMONITOR hMonitor, QWindowsScreenData *data) if (GetMonitorInfo(hMonitor, &info) == FALSE) return false; + data->hMonitor = hMonitor; data->geometry = QRect(QPoint(info.rcMonitor.left, info.rcMonitor.top), QPoint(info.rcMonitor.right - 1, info.rcMonitor.bottom - 1)); data->availableGeometry = QRect(QPoint(info.rcWork.left, info.rcWork.top), QPoint(info.rcWork.right - 1, info.rcWork.bottom - 1)); data->name = QString::fromWCharArray(info.szDevice); @@ -423,10 +417,7 @@ QPlatformScreen::SubpixelAntialiasingType QWindowsScreen::subpixelAntialiasingTy \ingroup qt-lighthouse-win */ -QWindowsScreenManager::QWindowsScreenManager() : - m_lastDepth(-1), m_lastHorizontalResolution(0), m_lastVerticalResolution(0) -{ -} +QWindowsScreenManager::QWindowsScreenManager() = default; /*! \brief Triggers synchronization of screens (WM_DISPLAYCHANGE). diff --git a/src/plugins/platforms/windows/qwindowsscreen.h b/src/plugins/platforms/windows/qwindowsscreen.h index 02a9dc3bc3..9a8997326b 100644 --- a/src/plugins/platforms/windows/qwindowsscreen.h +++ b/src/plugins/platforms/windows/qwindowsscreen.h @@ -59,18 +59,17 @@ struct QWindowsScreenData LockScreen = 0x4 // Temporary screen existing during user change, etc. }; - QWindowsScreenData(); - QRect geometry; QRect availableGeometry; - QDpi dpi; + QDpi dpi{96, 96}; QSizeF physicalSizeMM; - int depth; - QImage::Format format; - unsigned flags; + int depth = 32; + QImage::Format format = QImage::Format_ARGB32_Premultiplied; + unsigned flags = VirtualDesktop; QString name; - Qt::ScreenOrientation orientation; - qreal refreshRateHz; + Qt::ScreenOrientation orientation = Qt::LandscapeOrientation; + qreal refreshRateHz = 60; + HMONITOR hMonitor = nullptr; }; class QWindowsScreen : public QPlatformScreen @@ -82,23 +81,23 @@ public: explicit QWindowsScreen(const QWindowsScreenData &data); - QRect geometry() const Q_DECL_OVERRIDE { return m_data.geometry; } - QRect availableGeometry() const Q_DECL_OVERRIDE { return m_data.availableGeometry; } - int depth() const Q_DECL_OVERRIDE { return m_data.depth; } - QImage::Format format() const Q_DECL_OVERRIDE { return m_data.format; } - QSizeF physicalSize() const Q_DECL_OVERRIDE { return m_data.physicalSizeMM; } - QDpi logicalDpi() const Q_DECL_OVERRIDE { return m_data.dpi; } - qreal pixelDensity() const Q_DECL_OVERRIDE; - qreal devicePixelRatio() const Q_DECL_OVERRIDE { return 1.0; } - qreal refreshRate() const Q_DECL_OVERRIDE { return m_data.refreshRateHz; } - QString name() const Q_DECL_OVERRIDE { return m_data.name; } - Qt::ScreenOrientation orientation() const Q_DECL_OVERRIDE { return m_data.orientation; } - QList<QPlatformScreen *> virtualSiblings() const Q_DECL_OVERRIDE; - QWindow *topLevelAt(const QPoint &point) const Q_DECL_OVERRIDE; + QRect geometry() const override { return m_data.geometry; } + QRect availableGeometry() const override { return m_data.availableGeometry; } + int depth() const override { return m_data.depth; } + QImage::Format format() const override { return m_data.format; } + QSizeF physicalSize() const override { return m_data.physicalSizeMM; } + QDpi logicalDpi() const override { return m_data.dpi; } + qreal pixelDensity() const override; + qreal devicePixelRatio() const override { return 1.0; } + qreal refreshRate() const override { return m_data.refreshRateHz; } + QString name() const override { return m_data.name; } + Qt::ScreenOrientation orientation() const override { return m_data.orientation; } + QList<QPlatformScreen *> virtualSiblings() const override; + QWindow *topLevelAt(const QPoint &point) const override; static QWindow *windowAt(const QPoint &point, unsigned flags); - QPixmap grabWindow(WId window, int qX, int qY, int qWidth, int qHeight) const Q_DECL_OVERRIDE; - QPlatformScreen::SubpixelAntialiasingType subpixelAntialiasingTypeHint() const Q_DECL_OVERRIDE; + QPixmap grabWindow(WId window, int qX, int qY, int qWidth, int qHeight) const override; + QPlatformScreen::SubpixelAntialiasingType subpixelAntialiasingTypeHint() const override; static Qt::ScreenOrientation orientationPreference(); static bool setOrientationPreference(Qt::ScreenOrientation o); @@ -106,7 +105,7 @@ public: inline void handleChanges(const QWindowsScreenData &newData); #ifndef QT_NO_CURSOR - QPlatformCursor *cursor() const Q_DECL_OVERRIDE { return m_cursor.data(); } + QPlatformCursor *cursor() const override { return m_cursor.data(); } const CursorPtr &cursorPtr() const { return m_cursor; } #else QPlatformCursor *cursor() const { return 0; } @@ -140,9 +139,9 @@ private: void removeScreen(int index); WindowsScreenList m_screens; - int m_lastDepth; - WORD m_lastHorizontalResolution; - WORD m_lastVerticalResolution; + int m_lastDepth = -1; + WORD m_lastHorizontalResolution = 0; + WORD m_lastVerticalResolution = 0; }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/windows/qwindowsservices.cpp b/src/plugins/platforms/windows/qwindowsservices.cpp index 7f9c9bd205..48332b35f8 100644 --- a/src/plugins/platforms/windows/qwindowsservices.cpp +++ b/src/plugins/platforms/windows/qwindowsservices.cpp @@ -98,7 +98,11 @@ static inline QString mailCommand() RegQueryValueEx(handle, L"", 0, 0, reinterpret_cast<unsigned char*>(command), &bufferSize); RegCloseKey(handle); } - if (!command[0]) + // QTBUG-57816: As of Windows 10, if there is no mail client installed, an entry like + // "rundll32.exe .. url.dll,MailToProtocolHandler %l" is returned. Launching it + // silently fails or brings up a broken dialog after a long time, so exclude it and + // fall back to ShellExecute() which brings up the URL assocation dialog. + if (!command[0] || wcsstr(command, L",MailToProtocolHandler") != nullptr) return QString(); wchar_t expandedCommand[MAX_PATH] = {0}; return ExpandEnvironmentStrings(command, expandedCommand, MAX_PATH) ? diff --git a/src/plugins/platforms/windows/qwindowssessionmanager.cpp b/src/plugins/platforms/windows/qwindowssessionmanager.cpp index 2db9e44388..500fdc750c 100644 --- a/src/plugins/platforms/windows/qwindowssessionmanager.cpp +++ b/src/plugins/platforms/windows/qwindowssessionmanager.cpp @@ -44,9 +44,6 @@ QT_BEGIN_NAMESPACE QWindowsSessionManager::QWindowsSessionManager(const QString &id, const QString &key) : QPlatformSessionManager(id, key) - , m_isActive(false) - , m_blockUserInput(false) - , m_canceled(false) { } diff --git a/src/plugins/platforms/windows/qwindowssessionmanager.h b/src/plugins/platforms/windows/qwindowssessionmanager.h index 25d0636650..4c4256f2b0 100644 --- a/src/plugins/platforms/windows/qwindowssessionmanager.h +++ b/src/plugins/platforms/windows/qwindowssessionmanager.h @@ -59,15 +59,15 @@ class QWindowsSessionManager : public QPlatformSessionManager public: explicit QWindowsSessionManager(const QString &id, const QString &key); - bool allowsInteraction() Q_DECL_OVERRIDE; - bool allowsErrorInteraction() Q_DECL_OVERRIDE; + bool allowsInteraction() override; + bool allowsErrorInteraction() override; void blocksInteraction() { m_blockUserInput = true; } bool isInteractionBlocked() const { return m_blockUserInput; } - void release() Q_DECL_OVERRIDE; + void release() override; - void cancel() Q_DECL_OVERRIDE; + void cancel() override; void clearCancellation() { m_canceled = false; } bool wasCanceled() const { return m_canceled; } @@ -75,9 +75,9 @@ public: bool isActive() const { return m_isActive;} private: - bool m_isActive; - bool m_blockUserInput; - bool m_canceled; + bool m_isActive = false; + bool m_blockUserInput = false; + bool m_canceled = false; Q_DISABLE_COPY(QWindowsSessionManager) }; diff --git a/src/plugins/platforms/windows/qwindowstabletsupport.h b/src/plugins/platforms/windows/qwindowstabletsupport.h index 2c05dcddfc..97eceaf2cc 100644 --- a/src/plugins/platforms/windows/qwindowstabletsupport.h +++ b/src/plugins/platforms/windows/qwindowstabletsupport.h @@ -57,9 +57,6 @@ class QRect; struct QWindowsWinTab32DLL { - QWindowsWinTab32DLL() : wTOpen(0), wTClose(0), wTInfo(0), wTEnable(0), wTOverlap(0), wTPacketsGet(0), wTGet(0), - wTQueueSizeGet(0), wTQueueSizeSet(0) {} - bool init(); typedef HCTX (API *PtrWTOpen)(HWND, LPLOGCONTEXT, BOOL); @@ -72,15 +69,15 @@ struct QWindowsWinTab32DLL typedef int (API *PtrWTQueueSizeGet)(HCTX); typedef BOOL (API *PtrWTQueueSizeSet)(HCTX, int); - PtrWTOpen wTOpen; - PtrWTClose wTClose; - PtrWTInfo wTInfo; - PtrWTEnable wTEnable; - PtrWTOverlap wTOverlap; - PtrWTPacketsGet wTPacketsGet; - PtrWTGet wTGet; - PtrWTQueueSizeGet wTQueueSizeGet; - PtrWTQueueSizeSet wTQueueSizeSet; + PtrWTOpen wTOpen = nullptr; + PtrWTClose wTClose = nullptr; + PtrWTInfo wTInfo = nullptr; + PtrWTEnable wTEnable = nullptr; + PtrWTOverlap wTOverlap = nullptr; + PtrWTPacketsGet wTPacketsGet = nullptr; + PtrWTGet wTGet = nullptr; + PtrWTQueueSizeGet wTQueueSizeGet = nullptr; + PtrWTQueueSizeSet wTQueueSizeSet = nullptr; }; struct QWindowsTabletDeviceData diff --git a/src/plugins/platforms/windows/qwindowstheme.cpp b/src/plugins/platforms/windows/qwindowstheme.cpp index ed12c8124e..4ae1a751e9 100644 --- a/src/plugins/platforms/windows/qwindowstheme.cpp +++ b/src/plugins/platforms/windows/qwindowstheme.cpp @@ -61,6 +61,9 @@ #include <QtCore/QTextStream> #include <QtCore/QSysInfo> #include <QtCore/QCache> +#include <QtCore/QThread> +#include <QtCore/QMutex> +#include <QtCore/QWaitCondition> #include <QtGui/QColor> #include <QtGui/QPalette> #include <QtGui/QGuiApplication> @@ -127,40 +130,114 @@ static inline QColor getSysColor(int index) // QTBUG-48823/Windows 10: SHGetFileInfo() (as called by item views on file system // models has been observed to trigger a WM_PAINT on the mainwindow. Suppress the // behavior by running it in a thread. -class ShGetFileInfoFunction + +struct QShGetFileInfoParams +{ + QShGetFileInfoParams(const QString &fn, DWORD a, SHFILEINFO *i, UINT f, bool *r) + : fileName(fn), attributes(a), flags(f), info(i), result(r) + { } + + const QString &fileName; + const DWORD attributes; + const UINT flags; + SHFILEINFO *const info; + bool *const result; +}; + +class QShGetFileInfoThread : public QThread { public: - explicit ShGetFileInfoFunction(const wchar_t *fn, DWORD a, SHFILEINFO *i, UINT f, bool *r) : - m_fileName(fn), m_attributes(a), m_flags(f), m_info(i), m_result(r) {} + explicit QShGetFileInfoThread() + : QThread(), m_params(nullptr) + { + connect(this, &QThread::finished, this, &QObject::deleteLater); + } - void operator()() const + void run() override { + m_init = CoInitializeEx(NULL, COINIT_MULTITHREADED); + + QMutexLocker readyLocker(&m_readyMutex); + while (!m_cancelled.load()) { + if (!m_params && !m_cancelled.load() + && !m_readyCondition.wait(&m_readyMutex, 1000)) + continue; + + if (m_params) { + const QString fileName = m_params->fileName; + SHFILEINFO info; #ifndef Q_OS_WINCE - const UINT oldErrorMode = SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX); + const UINT oldErrorMode = SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX); #endif - *m_result = SHGetFileInfo(m_fileName, m_attributes, m_info, sizeof(SHFILEINFO), m_flags); + const bool result = SHGetFileInfo(reinterpret_cast<const wchar_t *>(fileName.utf16()), + m_params->attributes, &info, sizeof(SHFILEINFO), + m_params->flags); #ifndef Q_OS_WINCE - SetErrorMode(oldErrorMode); + SetErrorMode(oldErrorMode); #endif + m_doneMutex.lock(); + if (!m_cancelled.load()) { + *m_params->result = result; + memcpy(m_params->info, &info, sizeof(SHFILEINFO)); + } + m_params = nullptr; + + m_doneCondition.wakeAll(); + m_doneMutex.unlock(); + } + } + + if (m_init != S_FALSE) + CoUninitialize(); + } + + bool runWithParams(QShGetFileInfoParams *params, unsigned long timeOutMSecs) + { + QMutexLocker doneLocker(&m_doneMutex); + + m_readyMutex.lock(); + m_params = params; + m_readyCondition.wakeAll(); + m_readyMutex.unlock(); + + return m_doneCondition.wait(&m_doneMutex, timeOutMSecs); + } + + void cancel() + { + QMutexLocker doneLocker(&m_doneMutex); + m_cancelled.store(1); + m_readyCondition.wakeAll(); } private: - const wchar_t *m_fileName; - const DWORD m_attributes; - const UINT m_flags; - SHFILEINFO *const m_info; - bool *m_result; + HRESULT m_init; + QShGetFileInfoParams *m_params; + QAtomicInt m_cancelled; + QWaitCondition m_readyCondition; + QWaitCondition m_doneCondition; + QMutex m_readyMutex; + QMutex m_doneMutex; }; -static bool shGetFileInfoBackground(QWindowsThreadPoolRunner &r, - const wchar_t *fileName, DWORD attributes, +static bool shGetFileInfoBackground(const QString &fileName, DWORD attributes, SHFILEINFO *info, UINT flags, unsigned long timeOutMSecs = 5000) { + static QShGetFileInfoThread *getFileInfoThread = nullptr; + if (!getFileInfoThread) { + getFileInfoThread = new QShGetFileInfoThread; + getFileInfoThread->start(); + } + bool result = false; - if (!r.run(ShGetFileInfoFunction(fileName, attributes, info, flags, &result), timeOutMSecs)) { - qWarning().noquote() << "ShGetFileInfoBackground() timed out for " - << QString::fromWCharArray(fileName); + QShGetFileInfoParams params(fileName, attributes, info, flags, &result); + if (!getFileInfoThread->runWithParams(¶ms, timeOutMSecs)) { + // Cancel and reset getFileInfoThread. It'll + // be reinitialized the next time we get called. + getFileInfoThread->cancel(); + getFileInfoThread = nullptr; + qWarning().noquote() << "SHGetFileInfo() timed out for " << fileName; return false; } return result; @@ -315,7 +392,6 @@ const char *QWindowsTheme::name = "windows"; QWindowsTheme *QWindowsTheme::m_instance = 0; QWindowsTheme::QWindowsTheme() - : m_threadPoolRunner(new QWindowsThreadPoolRunner) { m_instance = this; std::fill(m_fonts, m_fonts + NFonts, static_cast<QFont *>(0)); @@ -718,10 +794,8 @@ static QPixmap pixmapFromShellImageList(int iImageList, const SHFILEINFO &info) class QWindowsFileIconEngine : public QAbstractFileIconEngine { public: - explicit QWindowsFileIconEngine(const QFileInfo &info, - QPlatformTheme::IconOptions opts, - const QSharedPointer<QWindowsThreadPoolRunner> &runner) : - QAbstractFileIconEngine(info, opts), m_threadPoolRunner(runner) {} + explicit QWindowsFileIconEngine(const QFileInfo &info, QPlatformTheme::IconOptions opts) : + QAbstractFileIconEngine(info, opts) {} QList<QSize> availableSizes(QIcon::Mode = QIcon::Normal, QIcon::State = QIcon::Off) const override { return QWindowsTheme::instance()->availableFileIconSizes(); } @@ -729,9 +803,6 @@ public: protected: QString cacheKey() const override; QPixmap filePixmap(const QSize &size, QIcon::Mode mode, QIcon::State) override; - -private: - const QSharedPointer<QWindowsThreadPoolRunner> m_threadPoolRunner; }; QString QWindowsFileIconEngine::cacheKey() const @@ -797,10 +868,8 @@ QPixmap QWindowsFileIconEngine::filePixmap(const QSize &size, QIcon::Mode, QIcon SHGFI_ICON|iconSize|SHGFI_SYSICONINDEX|SHGFI_ADDOVERLAYS|SHGFI_OVERLAYINDEX; const bool val = cacheableDirIcon && useDefaultFolderIcon - ? shGetFileInfoBackground(*m_threadPoolRunner.data(), L"dummy", FILE_ATTRIBUTE_DIRECTORY, - &info, flags | SHGFI_USEFILEATTRIBUTES) - : shGetFileInfoBackground(*m_threadPoolRunner.data(), reinterpret_cast<const wchar_t *>(filePath.utf16()), 0, - &info, flags); + ? shGetFileInfoBackground(QString::fromWCharArray(L"dummy"), FILE_ATTRIBUTE_DIRECTORY, &info, flags | SHGFI_USEFILEATTRIBUTES) + : shGetFileInfoBackground(filePath, 0, &info, flags); // Even if GetFileInfo returns a valid result, hIcon can be empty in some cases if (val && info.hIcon) { @@ -844,7 +913,7 @@ QPixmap QWindowsFileIconEngine::filePixmap(const QSize &size, QIcon::Mode, QIcon QIcon QWindowsTheme::fileIcon(const QFileInfo &fileInfo, QPlatformTheme::IconOptions iconOptions) const { - return QIcon(new QWindowsFileIconEngine(fileInfo, iconOptions, m_threadPoolRunner)); + return QIcon(new QWindowsFileIconEngine(fileInfo, iconOptions)); } QT_END_NAMESPACE diff --git a/src/plugins/platforms/windows/qwindowstheme.h b/src/plugins/platforms/windows/qwindowstheme.h index 0384899efa..a3019ff6eb 100644 --- a/src/plugins/platforms/windows/qwindowstheme.h +++ b/src/plugins/platforms/windows/qwindowstheme.h @@ -40,7 +40,6 @@ #ifndef QWINDOWSTHEME_H #define QWINDOWSTHEME_H -#include "qwindowsthreadpoolrunner.h" #include <qpa/qplatformtheme.h> #include <QtCore/QSharedPointer> @@ -58,15 +57,15 @@ public: static QWindowsTheme *instance() { return m_instance; } - bool usePlatformNativeDialog(DialogType type) const Q_DECL_OVERRIDE; - QPlatformDialogHelper *createPlatformDialogHelper(DialogType type) const Q_DECL_OVERRIDE; - QVariant themeHint(ThemeHint) const Q_DECL_OVERRIDE; - const QPalette *palette(Palette type = SystemPalette) const Q_DECL_OVERRIDE + bool usePlatformNativeDialog(DialogType type) const override; + QPlatformDialogHelper *createPlatformDialogHelper(DialogType type) const override; + QVariant themeHint(ThemeHint) const override; + const QPalette *palette(Palette type = SystemPalette) const override { return m_palettes[type]; } - const QFont *font(Font type = SystemFont) const Q_DECL_OVERRIDE + const QFont *font(Font type = SystemFont) const override { return m_fonts[type]; } - QPixmap standardPixmap(StandardPixmap sp, const QSizeF &size) const Q_DECL_OVERRIDE; + QPixmap standardPixmap(StandardPixmap sp, const QSizeF &size) const override; QIcon fileIcon(const QFileInfo &fileInfo, QPlatformTheme::IconOptions iconOptions = 0) const override; @@ -88,7 +87,6 @@ private: static QWindowsTheme *m_instance; QPalette *m_palettes[NPalettes]; QFont *m_fonts[NFonts]; - const QSharedPointer<QWindowsThreadPoolRunner> m_threadPoolRunner; QList<QSize> m_fileIconSizes; }; diff --git a/src/plugins/platforms/windows/qwindowsthreadpoolrunner.h b/src/plugins/platforms/windows/qwindowsthreadpoolrunner.h index 0361aa90f5..5601cc9305 100644 --- a/src/plugins/platforms/windows/qwindowsthreadpoolrunner.h +++ b/src/plugins/platforms/windows/qwindowsthreadpoolrunner.h @@ -1,31 +1,37 @@ /**************************************************************************** ** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ +** 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:LGPL21$ +** $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 http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. +** 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 2.1 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** 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. ** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** 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$ ** @@ -63,7 +69,7 @@ class QWindowsThreadPoolRunner explicit Runnable(QMutex *m, QWaitCondition *c, RunnableFunction f) : m_mutex(m), m_condition(c), m_function(f) {} - void run() Q_DECL_OVERRIDE + void run() override { m_function(); m_mutex->lock(); diff --git a/src/plugins/platforms/windows/qwindowswindow.cpp b/src/plugins/platforms/windows/qwindowswindow.cpp index 48835f26a6..2875463e62 100644 --- a/src/plugins/platforms/windows/qwindowswindow.cpp +++ b/src/plugins/platforms/windows/qwindowswindow.cpp @@ -118,6 +118,35 @@ static QByteArray debugWinExStyle(DWORD exStyle) return rc; } +static QByteArray debugWinSwpPos(UINT flags) +{ + QByteArray rc = "0x"; + rc += QByteArray::number(flags, 16); + if (flags & SWP_FRAMECHANGED) + rc += " SWP_FRAMECHANGED"; + if (flags & SWP_HIDEWINDOW) + rc += " SWP_HIDEWINDOW"; + if (flags & SWP_NOACTIVATE) + rc += " SWP_NOACTIVATE"; + if (flags & SWP_NOCOPYBITS) + rc += " SWP_NOCOPYBITS"; + if (flags & SWP_NOMOVE) + rc += " SWP_NOMOVE"; + if (flags & SWP_NOOWNERZORDER) + rc += " SWP_NOOWNERZORDER"; + if (flags & SWP_NOREDRAW) + rc += " SWP_NOREDRAW"; + if (flags & SWP_NOSENDCHANGING) + rc += " SWP_NOSENDCHANGING"; + if (flags & SWP_NOSIZE) + rc += " SWP_NOSIZE"; + if (flags & SWP_NOZORDER) + rc += " SWP_NOZORDER"; + if (flags & SWP_SHOWWINDOW) + rc += " SWP_SHOWWINDOW"; + return rc; +} + static inline QSize qSizeOfRect(const RECT &rect) { return QSize(rect.right -rect.left, rect.bottom - rect.top); @@ -141,8 +170,9 @@ QDebug operator<<(QDebug d, const RECT &r) { QDebugStateSaver saver(d); d.nospace(); - d << "RECT: left/top=" << r.left << ',' << r.top - << " right/bottom=" << r.right << ',' << r.bottom; + d << "RECT(left=" << r.left << ", top=" << r.top + << ", right=" << r.right << ", bottom=" << r.bottom + << " (" << r.right - r.left << 'x' << r.bottom - r.top << "))"; return d; } @@ -152,12 +182,23 @@ QDebug operator<<(QDebug d, const POINT &p) return d; } +QDebug operator<<(QDebug d, const WINDOWPOS &wp) +{ + QDebugStateSaver saver(d); + d.nospace(); + d.noquote(); + d << "WINDOWPOS(flags=" << debugWinSwpPos(wp.flags) << ", hwnd=" + << wp.hwnd << ", hwndInsertAfter=" << wp.hwndInsertAfter << ", x=" << wp.x + << ", y=" << wp.y << ", cx=" << wp.cx << ", cy=" << wp.cy << ')'; + return d; +} + QDebug operator<<(QDebug d, const NCCALCSIZE_PARAMS &p) { QDebugStateSaver saver(d); d.nospace(); - d << "NCCALCSIZE_PARAMS " << qrectFromRECT(p.rgrc[0]) - << ' ' << qrectFromRECT(p.rgrc[1]) << ' ' << qrectFromRECT(p.rgrc[2]); + d << "NCCALCSIZE_PARAMS(rgrc=[" << p.rgrc[0] << ' ' << p.rgrc[1] << ' ' + << p.rgrc[2] << "], lppos=" << *p.lppos << ')'; return d; } @@ -177,6 +218,7 @@ QDebug operator<<(QDebug d, const WINDOWPLACEMENT &wp) { QDebugStateSaver saver(d); d.nospace(); + d.noquote(); d << "WINDOWPLACEMENT(flags=0x" << hex << wp.flags << dec << ", showCmd=" << wp.showCmd << ", ptMinPosition=" << wp.ptMinPosition << ", ptMaxPosition=" << wp.ptMaxPosition << ", rcNormalPosition=" << wp.rcNormalPosition; @@ -939,9 +981,7 @@ QWindowCreationContext::QWindowCreationContext(const QWindow *w, DWORD style_, DWORD exStyle_) : geometryHint(w, cm), window(w), style(style_), exStyle(exStyle_), requestedGeometry(geometry), obtainedGeometry(geometry), - margins(QWindowsGeometryHint::frame(style, exStyle)), customMargins(cm), - frameX(CW_USEDEFAULT), frameY(CW_USEDEFAULT), - frameWidth(CW_USEDEFAULT), frameHeight(CW_USEDEFAULT) + margins(QWindowsGeometryHint::frame(style, exStyle)), customMargins(cm) { // Geometry of toplevels does not consider window frames. // TODO: No concept of WA_wasMoved yet that would indicate a @@ -994,17 +1034,8 @@ QWindowCreationContext::QWindowCreationContext(const QWindow *w, QWindowsWindow::QWindowsWindow(QWindow *aWindow, const QWindowsWindowData &data) : QWindowsBaseWindow(aWindow), m_data(data), - m_flags(WithinCreate), - m_hdc(0), - m_windowState(Qt::WindowNoState), - m_opacity(1.0), m_cursor(new CursorHandle), - m_dropTarget(0), - m_savedStyle(0), - m_format(aWindow->requestedFormat()), - m_iconSmall(0), - m_iconBig(0), - m_surface(0) + m_format(aWindow->requestedFormat()) { // Clear the creation context as the window can be found in QWindowsContext's map. QWindowsContext::instance()->setWindowCreationContext(QSharedPointer<QWindowCreationContext>()); @@ -1095,7 +1126,7 @@ void QWindowsWindow::updateDropSite(bool topLevel) // if the parent window is a foreign window wrapped via QWindow::fromWinId, we need to enable the drop site // on the first child window const QWindow *parent = window()->parent(); - if (parent && (parent->type() == Qt::ForeignWindow)) + if (parent && parent->handle() && parent->handle()->isForeignWindow()) parentIsEmbedded = true; } @@ -1216,18 +1247,14 @@ bool QWindowsWindow::isActive() const return false; } -bool QWindowsWindow::isEmbedded(const QPlatformWindow *parentWindow) const +bool QWindowsWindow::isAncestorOf(const QPlatformWindow *child) const { - if (parentWindow) { - const QWindowsWindow *ww = static_cast<const QWindowsWindow *>(parentWindow); - const HWND hwnd = ww->handle(); - if (!IsChild(hwnd, m_data.hwnd)) - return false; - } - - if (!m_data.embedded && parent()) - return parent()->isEmbedded(); + const QWindowsWindow *childWindow = static_cast<const QWindowsWindow *>(child); + return IsChild(m_data.hwnd, childWindow->handle()); +} +bool QWindowsWindow::isEmbedded() const +{ return m_data.embedded; } @@ -1471,18 +1498,22 @@ void QWindowsWindow::handleResized(int wParam) case SIZE_MAXHIDE: // Some other window affected. case SIZE_MAXSHOW: return; - case SIZE_MINIMIZED: - handleWindowStateChange(Qt::WindowMinimized); + case SIZE_MINIMIZED: // QTBUG-53577, prevent state change events during programmatic state change + if (!testFlag(WithinSetStyle)) + handleWindowStateChange(Qt::WindowMinimized); return; case SIZE_MAXIMIZED: - handleWindowStateChange(Qt::WindowMaximized); + if (!testFlag(WithinSetStyle)) + handleWindowStateChange(Qt::WindowMaximized); handleGeometryChange(); break; case SIZE_RESTORED: - if (isFullScreen_sys()) - handleWindowStateChange(Qt::WindowFullScreen); - else if (m_windowState != Qt::WindowNoState && !testFlag(MaximizeToFullScreen)) - handleWindowStateChange(Qt::WindowNoState); + if (!testFlag(WithinSetStyle)) { + if (isFullScreen_sys()) + handleWindowStateChange(Qt::WindowFullScreen); + else if (m_windowState != Qt::WindowNoState && !testFlag(MaximizeToFullScreen)) + handleWindowStateChange(Qt::WindowNoState); + } handleGeometryChange(); break; } @@ -1490,9 +1521,6 @@ void QWindowsWindow::handleResized(int wParam) void QWindowsWindow::handleGeometryChange() { - //Prevent recursive resizes for Windows CE - if (testFlag(WithinSetStyle)) - return; const QRect previousGeometry = m_data.geometry; m_data.geometry = geometry_sys(); QPlatformWindow::setGeometry(m_data.geometry); @@ -1505,10 +1533,16 @@ void QWindowsWindow::handleGeometryChange() && !(m_data.geometry.width() > previousGeometry.width() || m_data.geometry.height() > previousGeometry.height())) { fireExpose(QRect(QPoint(0, 0), m_data.geometry.size()), true); } - if (previousGeometry.topLeft() != m_data.geometry.topLeft()) { - QPlatformScreen *newScreen = screenForGeometry(m_data.geometry); - if (newScreen != screen()) - QWindowSystemInterface::handleWindowScreenChanged(window(), newScreen->screen()); + if (!parent() && previousGeometry.topLeft() != m_data.geometry.topLeft()) { + HMONITOR hMonitor = MonitorFromWindow(m_data.hwnd, MONITOR_DEFAULTTONULL); + QPlatformScreen *currentScreen = screen(); + const auto screens = QWindowsContext::instance()->screenManager().screens(); + auto newScreenIt = std::find_if(screens.begin(), screens.end(), [&](QWindowsScreen *s) { + return s->data().hMonitor == hMonitor + && s->data().flags & QWindowsScreenData::VirtualDesktop; + }); + if (newScreenIt != screens.end() && *newScreenIt != currentScreen) + QWindowSystemInterface::handleWindowScreenChanged(window(), (*newScreenIt)->screen()); } if (testFlag(SynchronousGeometryChangeEvent)) QWindowSystemInterface::flushWindowSystemEvents(QEventLoop::ExcludeUserInputEvents); @@ -1588,7 +1622,8 @@ bool QWindowsWindow::handleWmPaint(HWND hwnd, UINT message, if (message == WM_ERASEBKGND) // Backing store - ignored. return true; // Ignore invalid update bounding rectangles - if (!GetUpdateRect(m_data.hwnd, 0, FALSE)) + RECT updateRect; + if (!GetUpdateRect(m_data.hwnd, &updateRect, FALSE)) return false; PAINTSTRUCT ps; @@ -1612,7 +1647,7 @@ bool QWindowsWindow::handleWmPaint(HWND hwnd, UINT message, // we still need to send isExposed=true, for compatibility. // Our tests depend on it. fireExpose(QRegion(qrectFromRECT(ps.rcPaint)), true); - if (!QWindowsContext::instance()->asyncExpose()) + if (qSizeOfRect(updateRect) == m_data.geometry.size() && !QWindowsContext::instance()->asyncExpose()) QWindowSystemInterface::flushWindowSystemEvents(QEventLoop::ExcludeUserInputEvents); EndPaint(hwnd, &ps); @@ -1659,7 +1694,6 @@ QWindowsWindowData QWindowsWindow::setWindowFlags_sys(Qt::WindowFlags wt, QWindowsWindowData result = m_data; result.flags = creationData.flags; result.embedded = creationData.embedded; - setFlag(FrameDirty); return result; } @@ -1667,7 +1701,6 @@ void QWindowsWindow::handleWindowStateChange(Qt::WindowState state) { qCDebug(lcQpaWindows) << __FUNCTION__ << this << window() << "\n from " << m_windowState << " to " << state; - setFlag(FrameDirty); m_windowState = state; QWindowSystemInterface::handleWindowStateChanged(window(), state); switch (state) { @@ -1717,10 +1750,9 @@ bool QWindowsWindow::isFullScreen_sys() const const QWindow *w = window(); if (!w->isTopLevel()) return false; - const QScreen *screen = w->screen(); - if (!screen) - screen = QGuiApplication::primaryScreen(); - return screen && geometry_sys() == QHighDpi::toNativePixels(screen->geometry(), w); + QRect geometry = geometry_sys(); + QPlatformScreen *screen = screenForGeometry(geometry); + return screen && geometry == QHighDpi::toNativePixels(screen->geometry(), screen); } /*! @@ -1744,8 +1776,6 @@ void QWindowsWindow::setWindowState_sys(Qt::WindowState newState) const bool visible = isVisible(); - setFlag(FrameDirty); - if ((oldState == Qt::WindowFullScreen) != (newState == Qt::WindowFullScreen)) { if (newState == Qt::WindowFullScreen) { #ifndef Q_FLATTEN_EXPOSE @@ -1794,6 +1824,13 @@ void QWindowsWindow::setWindowState_sys(Qt::WindowState newState) newStyle |= WS_VISIBLE; setStyle(newStyle); + const QScreen *screen = window()->screen(); + if (!screen) + screen = QGuiApplication::primaryScreen(); + // That area of the virtual desktop might not be covered by a screen anymore. + if (!screen->geometry().intersects(m_savedFrameGeometry)) + m_savedFrameGeometry.moveTo(screen->geometry().topLeft()); + UINT swpf = SWP_FRAMECHANGED | SWP_NOZORDER | SWP_NOACTIVATE; if (!m_savedFrameGeometry.isValid()) swpf |= SWP_NOSIZE | SWP_NOMOVE; @@ -1839,7 +1876,6 @@ void QWindowsWindow::setStyle(unsigned s) const { qCDebug(lcQpaWindows) << __FUNCTION__ << this << window() << debugWinStyle(s); setFlag(WithinSetStyle); - setFlag(FrameDirty); SetWindowLongPtr(m_data.hwnd, GWL_STYLE, s); clearFlag(WithinSetStyle); } @@ -1848,7 +1884,6 @@ void QWindowsWindow::setExStyle(unsigned s) const { qCDebug(lcQpaWindows).nospace() << __FUNCTION__ << ' ' << this << ' ' << window() << " 0x" << QByteArray::number(s, 16); - setFlag(FrameDirty); SetWindowLongPtr(m_data.hwnd, GWL_EXSTYLE, s); } @@ -1904,22 +1939,17 @@ bool QWindowsWindow::handleGeometryChanging(MSG *message) const return QWindowsWindow::handleGeometryChangingMessage(message, window(), margins); } -QMargins QWindowsWindow::frameMargins() const +void QWindowsWindow::setFrameMargins(const QMargins &newMargins) { - // Frames are invalidated by style changes (window state, flags). - // As they are also required for geometry calculations in resize - // event sequences, introduce a dirty flag mechanism to be able - // to cache results. - if (testFlag(FrameDirty)) { - // Always skip calculating style-dependent margins for windows claimed to be frameless. - // This allows users to remove the margins by handling WM_NCCALCSIZE with WS_THICKFRAME set - // to ensure Areo snap still works (QTBUG-40578). - m_data.frame = m_data.flags & Qt::FramelessWindowHint - ? QMargins(0, 0, 0, 0) - : QWindowsGeometryHint::frame(style(), exStyle()); - clearFlag(FrameDirty); + if (m_data.frame != newMargins) { + qCDebug(lcQpaWindows) << __FUNCTION__ << window() << m_data.frame << "->" << newMargins; + m_data.frame = newMargins; } - return m_data.frame + m_data.customMargins; +} + +QMargins QWindowsWindow::frameMargins() const +{ + return m_data.frame; } void QWindowsWindow::setOpacity(qreal level) @@ -2091,8 +2121,12 @@ void QWindowsWindow::setFrameStrutEventsEnabled(bool enabled) void QWindowsWindow::getSizeHints(MINMAXINFO *mmi) const { - const QWindowsGeometryHint hint(window(), m_data.customMargins); - hint.applyToMinMaxInfo(m_data.hwnd, mmi); + // We don't apply the min/max size hint as we change the dpi, because we did not adjust the + // QScreen of the window yet so we don't have the min/max with the right ratio + if (!testFlag(QWindowsWindow::WithinDpiChanged)) { + const QWindowsGeometryHint hint(window(), m_data.customMargins); + hint.applyToMinMaxInfo(m_data.hwnd, mmi); + } if ((testFlag(WithinMaximize) || (window()->windowState() == Qt::WindowMinimized)) && (m_data.flags & Qt::FramelessWindowHint)) { @@ -2335,7 +2369,6 @@ void QWindowsWindow::setCustomMargins(const QMargins &newCustomMargins) const QPoint topLeft = currentFrameGeometry.topLeft(); QRect newFrame = currentFrameGeometry.marginsRemoved(oldCustomMargins) + m_data.customMargins; newFrame.moveTo(topLeft); - setFlag(FrameDirty); qCDebug(lcQpaWindows) << __FUNCTION__ << oldCustomMargins << "->" << newCustomMargins << currentFrameGeometry << "->" << newFrame; SetWindowPos(m_data.hwnd, 0, newFrame.x(), newFrame.y(), newFrame.width(), newFrame.height(), SWP_NOZORDER | SWP_FRAMECHANGED); @@ -2378,7 +2411,8 @@ void QWindowsWindow::setTouchWindowTouchTypeStatic(QWindow *window, QWindowsWind void QWindowsWindow::registerTouchWindow(QWindowsWindowFunctions::TouchWindowTouchTypes touchTypes) { - if ((QWindowsContext::instance()->systemInfo() & QWindowsContext::SI_SupportsTouch)) { + if ((QWindowsContext::instance()->systemInfo() & QWindowsContext::SI_SupportsTouch) + && !testFlag(TouchRegistered)) { ULONG touchFlags = 0; const bool ret = QWindowsContext::user32dll.isTouchWindow(m_data.hwnd, &touchFlags); // Return if it is not a touch window or the flags are already set by a hook diff --git a/src/plugins/platforms/windows/qwindowswindow.h b/src/plugins/platforms/windows/qwindowswindow.h index 924f242e6e..e541b110a6 100644 --- a/src/plugins/platforms/windows/qwindowswindow.h +++ b/src/plugins/platforms/windows/qwindowswindow.h @@ -89,22 +89,20 @@ struct QWindowCreationContext QRect obtainedGeometry; QMargins margins; QMargins customMargins; // User-defined, additional frame for WM_NCCALCSIZE - int frameX; // Passed on to CreateWindowEx(), including frame. - int frameY; - int frameWidth; - int frameHeight; + int frameX = CW_USEDEFAULT; // Passed on to CreateWindowEx(), including frame. + int frameY = CW_USEDEFAULT; + int frameWidth = CW_USEDEFAULT; + int frameHeight = CW_USEDEFAULT; }; struct QWindowsWindowData { - QWindowsWindowData() : hwnd(0), embedded(false) {} - Qt::WindowFlags flags; QRect geometry; QMargins frame; // Do not use directly for windows, see FrameDirty. QMargins customMargins; // User-defined, additional frame for NCCALCSIZE - HWND hwnd; - bool embedded; + HWND hwnd = 0; + bool embedded = false; static QWindowsWindowData create(const QWindow *w, const QWindowsWindowData ¶meters, @@ -116,11 +114,11 @@ class QWindowsBaseWindow : public QPlatformWindow public: explicit QWindowsBaseWindow(QWindow *window) : QPlatformWindow(window) {} - WId winId() const Q_DECL_OVERRIDE { return WId(handle()); } - QRect geometry() const Q_DECL_OVERRIDE { return geometry_sys(); } - QMargins frameMargins() const Q_DECL_OVERRIDE { return frameMargins_sys(); } - QPoint mapToGlobal(const QPoint &pos) const Q_DECL_OVERRIDE; - QPoint mapFromGlobal(const QPoint &pos) const Q_DECL_OVERRIDE; + WId winId() const override { return WId(handle()); } + QRect geometry() const override { return geometry_sys(); } + QMargins frameMargins() const override { return frameMargins_sys(); } + QPoint mapToGlobal(const QPoint &pos) const override; + QPoint mapFromGlobal(const QPoint &pos) const override; using QPlatformWindow::screenForGeometry; @@ -152,11 +150,11 @@ public: explicit QWindowsDesktopWindow(QWindow *window) : QWindowsBaseWindow(window), m_hwnd(GetDesktopWindow()) {} - QMargins frameMargins() const Q_DECL_OVERRIDE { return QMargins(); } - bool isTopLevel() const Q_DECL_OVERRIDE { return true; } + QMargins frameMargins() const override { return QMargins(); } + bool isTopLevel() const override { return true; } protected: - HWND handle() const Q_DECL_OVERRIDE { return m_hwnd; } + HWND handle() const override { return m_hwnd; } private: const HWND m_hwnd; @@ -167,15 +165,16 @@ class QWindowsForeignWindow : public QWindowsBaseWindow public: explicit QWindowsForeignWindow(QWindow *window, HWND hwnd); - void setParent(const QPlatformWindow *window) Q_DECL_OVERRIDE; - void setGeometry(const QRect &rect) Q_DECL_OVERRIDE { setGeometry_sys(rect); } - void setVisible(bool visible) Q_DECL_OVERRIDE; - void raise() Q_DECL_OVERRIDE { raise_sys(); } - void lower() Q_DECL_OVERRIDE { lower_sys(); } - void setWindowTitle(const QString &title) Q_DECL_OVERRIDE { setWindowTitle_sys(title); } + void setParent(const QPlatformWindow *window) override; + void setGeometry(const QRect &rect) override { setGeometry_sys(rect); } + void setVisible(bool visible) override; + void raise() override { raise_sys(); } + void lower() override { lower_sys(); } + void setWindowTitle(const QString &title) override { setWindowTitle_sys(title); } + bool isForeignWindow() const override { return true; } protected: - HWND handle() const Q_DECL_OVERRIDE { return m_hwnd; } + HWND handle() const override { return m_hwnd; } private: const HWND m_hwnd; @@ -189,7 +188,6 @@ public: { AutoMouseCapture = 0x1, //! Automatic mouse capture on button press. WithinSetParent = 0x2, - FrameDirty = 0x4, //! Frame outdated by setStyle, recalculate in next query. OpenGLSurface = 0x10, OpenGL_ES2 = 0x20, OpenGLDoubleBuffered = 0x40, @@ -208,7 +206,8 @@ public: MaximizeToFullScreen = 0x80000, InputMethodDisabled = 0x100000, Compositing = 0x200000, - HasBorderInFullScreen = 0x400000 + HasBorderInFullScreen = 0x400000, + WithinDpiChanged = 0x800000, }; QWindowsWindow(QWindow *window, const QWindowsWindowData &data); @@ -216,52 +215,54 @@ public: using QPlatformWindow::screenForGeometry; - QSurfaceFormat format() const Q_DECL_OVERRIDE { return m_format; } - void setGeometry(const QRect &rect) Q_DECL_OVERRIDE; - QRect geometry() const Q_DECL_OVERRIDE { return m_data.geometry; } - QRect normalGeometry() const Q_DECL_OVERRIDE; + QSurfaceFormat format() const override { return m_format; } + void setGeometry(const QRect &rect) override; + QRect geometry() const override { return m_data.geometry; } + QRect normalGeometry() const override; - void setVisible(bool visible) Q_DECL_OVERRIDE; + void setVisible(bool visible) override; bool isVisible() const; - bool isExposed() const Q_DECL_OVERRIDE { return testFlag(Exposed); } - bool isActive() const Q_DECL_OVERRIDE; - bool isEmbedded(const QPlatformWindow *parentWindow = 0) const Q_DECL_OVERRIDE; - QPoint mapToGlobal(const QPoint &pos) const Q_DECL_OVERRIDE; - QPoint mapFromGlobal(const QPoint &pos) const Q_DECL_OVERRIDE; + bool isExposed() const override { return testFlag(Exposed); } + bool isActive() const override; + bool isAncestorOf(const QPlatformWindow *child) const override; + bool isEmbedded() const override; + QPoint mapToGlobal(const QPoint &pos) const override; + QPoint mapFromGlobal(const QPoint &pos) const override; - void setWindowFlags(Qt::WindowFlags flags) Q_DECL_OVERRIDE; - void setWindowState(Qt::WindowState state) Q_DECL_OVERRIDE; + void setWindowFlags(Qt::WindowFlags flags) override; + void setWindowState(Qt::WindowState state) override; - void setParent(const QPlatformWindow *window) Q_DECL_OVERRIDE; + void setParent(const QPlatformWindow *window) override; - void setWindowTitle(const QString &title) Q_DECL_OVERRIDE; - void raise() Q_DECL_OVERRIDE { raise_sys(); } - void lower() Q_DECL_OVERRIDE { lower_sys(); } + void setWindowTitle(const QString &title) override; + void raise() override { raise_sys(); } + void lower() override { lower_sys(); } - void windowEvent(QEvent *event) Q_DECL_OVERRIDE; + void windowEvent(QEvent *event) override; - void propagateSizeHints() Q_DECL_OVERRIDE; + void propagateSizeHints() override; static bool handleGeometryChangingMessage(MSG *message, const QWindow *qWindow, const QMargins &marginsDp); bool handleGeometryChanging(MSG *message) const; - QMargins frameMargins() const Q_DECL_OVERRIDE; + QMargins frameMargins() const override; + void setFrameMargins(const QMargins &newMargins); - void setOpacity(qreal level) Q_DECL_OVERRIDE; - void setMask(const QRegion ®ion) Q_DECL_OVERRIDE; + void setOpacity(qreal level) override; + void setMask(const QRegion ®ion) override; qreal opacity() const { return m_opacity; } - void requestActivateWindow() Q_DECL_OVERRIDE; + void requestActivateWindow() override; - bool setKeyboardGrabEnabled(bool grab) Q_DECL_OVERRIDE; - bool setMouseGrabEnabled(bool grab) Q_DECL_OVERRIDE; + bool setKeyboardGrabEnabled(bool grab) override; + bool setMouseGrabEnabled(bool grab) override; inline bool hasMouseCapture() const { return GetCapture() == m_data.hwnd; } - bool startSystemResize(const QPoint &pos, Qt::Corner corner) Q_DECL_OVERRIDE; + bool startSystemResize(const QPoint &pos, Qt::Corner corner) override; - void setFrameStrutEventsEnabled(bool enabled) Q_DECL_OVERRIDE; - bool frameStrutEventsEnabled() const Q_DECL_OVERRIDE { return testFlag(FrameStrutEventsEnabled); } + void setFrameStrutEventsEnabled(bool enabled) override; + bool frameStrutEventsEnabled() const override { return testFlag(FrameStrutEventsEnabled); } // QWindowsBaseWindow overrides - HWND handle() const Q_DECL_OVERRIDE { return m_data.hwnd; } - bool isTopLevel() const Q_DECL_OVERRIDE; + HWND handle() const override { return m_data.hwnd; } + bool isTopLevel() const override; QMargins customMargins() const { return m_data.customMargins; } void setCustomMargins(const QMargins &m); @@ -301,14 +302,14 @@ public: void setEnabled(bool enabled); bool isEnabled() const; - void setWindowIcon(const QIcon &icon) Q_DECL_OVERRIDE; + void setWindowIcon(const QIcon &icon) override; void *surface(void *nativeConfig, int *err); - void invalidateSurface() Q_DECL_OVERRIDE; + void invalidateSurface() override; void aboutToMakeCurrent(); - void setAlertState(bool enabled) Q_DECL_OVERRIDE; - bool isAlertState() const Q_DECL_OVERRIDE { return testFlag(AlertState); } + void setAlertState(bool enabled) override; + bool isAlertState() const override { return testFlag(AlertState); } void alertWindow(int durationMs = 0); void stopAlertWindow(); @@ -335,20 +336,20 @@ private: void fireExpose(const QRegion ®ion, bool force=false); mutable QWindowsWindowData m_data; - mutable unsigned m_flags; - HDC m_hdc; - Qt::WindowState m_windowState; - qreal m_opacity; + mutable unsigned m_flags = WithinCreate; + HDC m_hdc = 0; + Qt::WindowState m_windowState = Qt::WindowNoState; + qreal m_opacity = 1; #ifndef QT_NO_CURSOR CursorHandlePtr m_cursor; #endif - QWindowsOleDropTarget *m_dropTarget; - unsigned m_savedStyle; + QWindowsOleDropTarget *m_dropTarget = nullptr; + unsigned m_savedStyle = 0; QRect m_savedFrameGeometry; const QSurfaceFormat m_format; - HICON m_iconSmall; - HICON m_iconBig; - void *m_surface; + HICON m_iconSmall = 0; + HICON m_iconBig = 0; + void *m_surface = nullptr; }; #ifndef QT_NO_DEBUG_STREAM @@ -357,6 +358,7 @@ QDebug operator<<(QDebug d, const POINT &); QDebug operator<<(QDebug d, const MINMAXINFO &i); QDebug operator<<(QDebug d, const NCCALCSIZE_PARAMS &p); QDebug operator<<(QDebug d, const WINDOWPLACEMENT &); +QDebug operator<<(QDebug d, const WINDOWPOS &); #endif // !QT_NO_DEBUG_STREAM // ---------- QWindowsGeometryHint inline functions. @@ -385,15 +387,14 @@ QPoint QWindowsGeometryHint::mapFromGlobal(const QWindow *w, const QPoint &p) inline QWindowsWindow *QWindowsWindow::windowsWindowOf(const QWindow *w) { - QWindowsWindow *result = Q_NULLPTR; - if (w) { - const Qt::WindowType type = w->type(); - if (type != Qt::Desktop && type != Qt::ForeignWindow) { - if (QPlatformWindow *pw = w->handle()) - result = static_cast<QWindowsWindow *>(pw); - } - } - return result; + if (!w || !w->handle()) + return nullptr; + + const Qt::WindowType type = w->type(); + if (type == Qt::Desktop || w->handle()->isForeignWindow()) + return nullptr; + + return static_cast<QWindowsWindow *>(w->handle()); } void *QWindowsWindow::userDataOf(HWND hwnd) diff --git a/src/plugins/platforms/windows/windows.pri b/src/plugins/platforms/windows/windows.pri index 20e0b81da9..7d3ecc8aa2 100644 --- a/src/plugins/platforms/windows/windows.pri +++ b/src/plugins/platforms/windows/windows.pri @@ -99,5 +99,5 @@ RESOURCES += $$PWD/openglblacklists.qrc qtConfig(accessibility): include($$PWD/accessible/accessible.pri) -DEFINES *= LIBEGL_NAME=$${LIBEGL_NAME} -DEFINES *= LIBGLESV2_NAME=$${LIBGLESV2_NAME} +DEFINES *= LIBEGL_NAME=$${LIBQTANGLE_NAME} +DEFINES *= LIBGLESV2_NAME=$${LIBQTANGLE_NAME} diff --git a/src/plugins/platforms/winrt/qwinrtclipboard.cpp b/src/plugins/platforms/winrt/qwinrtclipboard.cpp index 0a38b3df34..117cb515df 100644 --- a/src/plugins/platforms/winrt/qwinrtclipboard.cpp +++ b/src/plugins/platforms/winrt/qwinrtclipboard.cpp @@ -61,7 +61,6 @@ QT_BEGIN_NAMESPACE QWinRTClipboard::QWinRTClipboard() : m_mimeData(Q_NULLPTR) { -#ifndef Q_OS_WINPHONE QEventDispatcherWinRT::runOnXamlThread([this]() { HRESULT hr; hr = GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_ApplicationModel_DataTransfer_Clipboard).Get(), @@ -74,7 +73,6 @@ QWinRTClipboard::QWinRTClipboard() return hr; }); -#endif // !Q_OS_WINPHONE } QMimeData *QWinRTClipboard::mimeData(QClipboard::Mode mode) @@ -82,7 +80,6 @@ QMimeData *QWinRTClipboard::mimeData(QClipboard::Mode mode) if (!supportsMode(mode)) return nullptr; -#ifndef Q_OS_WINPHONE ComPtr<IDataPackageView> view; HRESULT hr; hr = m_nativeClipBoard->GetContent(&view); @@ -114,9 +111,6 @@ QMimeData *QWinRTClipboard::mimeData(QClipboard::Mode mode) m_mimeData->setText(text); return m_mimeData; -#else // Q_OS_WINPHONE - return QPlatformClipboard::mimeData(mode); -#endif // Q_OS_WINPHONE } // Inspired by QWindowsMimeText::convertFromMime @@ -153,7 +147,6 @@ void QWinRTClipboard::setMimeData(QMimeData *data, QClipboard::Mode mode) if (!supportsMode(mode)) return; -#ifndef Q_OS_WINPHONE const bool newData = !m_mimeData || m_mimeData != data; if (newData) { if (m_mimeData) @@ -178,18 +171,11 @@ void QWinRTClipboard::setMimeData(QMimeData *data, QClipboard::Mode mode) return S_OK; }); RETURN_VOID_IF_FAILED("Could not set clipboard text."); -#else // Q_OS_WINPHONE - QPlatformClipboard::setMimeData(data, mode); -#endif // Q_OS_WINPHONE } bool QWinRTClipboard::supportsMode(QClipboard::Mode mode) const { -#ifndef Q_OS_WINPHONE return mode == QClipboard::Clipboard; -#else - return QPlatformClipboard::supportsMode(mode); -#endif } HRESULT QWinRTClipboard::onContentChanged(IInspectable *, IInspectable *) diff --git a/src/plugins/platforms/winrt/qwinrtclipboard.h b/src/plugins/platforms/winrt/qwinrtclipboard.h index 2e3e2b834d..899fcbe730 100644 --- a/src/plugins/platforms/winrt/qwinrtclipboard.h +++ b/src/plugins/platforms/winrt/qwinrtclipboard.h @@ -45,7 +45,6 @@ #include <wrl.h> -#ifndef Q_OS_WINPHONE namespace ABI { namespace Windows { namespace ApplicationModel { @@ -55,7 +54,6 @@ namespace ABI { } } } -#endif // !Q_OS_WINPHONE QT_BEGIN_NAMESPACE @@ -70,9 +68,7 @@ public: HRESULT onContentChanged(IInspectable *, IInspectable *); private: -#ifndef Q_OS_WINPHONE Microsoft::WRL::ComPtr<ABI::Windows::ApplicationModel::DataTransfer::IClipboardStatics> m_nativeClipBoard; -#endif QMimeData *m_mimeData; }; diff --git a/src/plugins/platforms/winrt/qwinrtdrag.cpp b/src/plugins/platforms/winrt/qwinrtdrag.cpp index 89ebf7d26f..cf52816b65 100644 --- a/src/plugins/platforms/winrt/qwinrtdrag.cpp +++ b/src/plugins/platforms/winrt/qwinrtdrag.cpp @@ -504,6 +504,8 @@ static HRESULT qt_drop(IInspectable *sender, ABI::Windows::UI::Xaml::IDragEventA class QtDragEventHandler##name : public IDragEventHandler \ { \ public: \ + virtual ~QtDragEventHandler##name() {\ + }\ STDMETHODIMP Invoke(IInspectable *sender, \ ABI::Windows::UI::Xaml::IDragEventArgs *e) \ { \ diff --git a/src/plugins/platforms/winrt/qwinrtfiledialoghelper.cpp b/src/plugins/platforms/winrt/qwinrtfiledialoghelper.cpp index 417dbdc1db..62eacba89b 100644 --- a/src/plugins/platforms/winrt/qwinrtfiledialoghelper.cpp +++ b/src/plugins/platforms/winrt/qwinrtfiledialoghelper.cpp @@ -61,11 +61,9 @@ using namespace ABI::Windows::Foundation::Collections; using namespace ABI::Windows::Storage; using namespace ABI::Windows::Storage::Pickers; -#ifndef Q_OS_WINPHONE typedef IAsyncOperationCompletedHandler<StorageFile *> SingleFileHandler; typedef IAsyncOperationCompletedHandler<IVectorView<StorageFile *> *> MultipleFileHandler; typedef IAsyncOperationCompletedHandler<StorageFolder *> SingleFolderHandler; -#endif QT_BEGIN_NAMESPACE @@ -152,16 +150,6 @@ private: QVector<HSTRING> impl; }; -#ifdef Q_OS_WINPHONE -class QActivationEvent : public QEvent -{ -public: - IInspectable *args() const { - return reinterpret_cast<IInspectable *>(d); - } -}; -#endif - template<typename T> static bool initializePicker(HSTRING runtimeId, T **picker, const QSharedPointer<QFileDialogOptions> &options) { @@ -225,23 +213,6 @@ static bool pickFiles(IFileOpenPicker *picker, QWinRTFileDialogHelper *helper, b Q_ASSERT(picker); Q_ASSERT(helper); HRESULT hr; -#ifdef Q_OS_WINPHONE - hr = QEventDispatcherWinRT::runOnXamlThread([picker, singleFile]() { - HRESULT hr; - ComPtr<IFileOpenPicker2> picker2; - hr = picker->QueryInterface(IID_PPV_ARGS(picker2.GetAddressOf())); - RETURN_HR_IF_FAILED("Failed to cast file picker"); - if (singleFile) - return picker2->PickSingleFileAndContinue(); - else - return picker2->PickMultipleFilesAndContinue(); - }); - RETURN_FALSE_IF_FAILED("Failed to open file picker"); - QAbstractEventDispatcher *eventDispatcher = QCoreApplication::eventDispatcher(); - Q_ASSERT(eventDispatcher); - eventDispatcher->installEventFilter(helper); - return true; -#else hr = QEventDispatcherWinRT::runOnXamlThread([picker, helper, singleFile]() { HRESULT hr; if (singleFile) { @@ -260,7 +231,6 @@ static bool pickFiles(IFileOpenPicker *picker, QWinRTFileDialogHelper *helper, b return S_OK; }); return SUCCEEDED(hr); -#endif } static bool pickFolder(IFolderPicker *picker, QWinRTFileDialogHelper *helper) @@ -268,19 +238,6 @@ static bool pickFolder(IFolderPicker *picker, QWinRTFileDialogHelper *helper) Q_ASSERT(picker); Q_ASSERT(helper); HRESULT hr; -#ifdef Q_OS_WINPHONE - hr = QEventDispatcherWinRT::runOnXamlThread([picker]() { - HRESULT hr; - ComPtr<IFolderPicker2> picker2; - hr = picker->QueryInterface(IID_PPV_ARGS(picker2.GetAddressOf())); - RETURN_HR_IF_FAILED("Failed to cast folder picker"); - return picker2->PickFolderAndContinue(); - }); - RETURN_FALSE_IF_FAILED("Failed to open folder picker"); - QAbstractEventDispatcher *eventDispatcher = QCoreApplication::eventDispatcher(); - Q_ASSERT(eventDispatcher); - eventDispatcher->installEventFilter(helper); -#else hr = QEventDispatcherWinRT::runOnXamlThread([picker, helper]() { HRESULT hr; ComPtr<IAsyncOperation<StorageFolder *>> op; @@ -290,7 +247,6 @@ static bool pickFolder(IFolderPicker *picker, QWinRTFileDialogHelper *helper) RETURN_HR_IF_FAILED("Failed to attach folder picker callback"); return S_OK; }); -#endif return SUCCEEDED(hr); } @@ -299,19 +255,6 @@ static bool pickSaveFile(IFileSavePicker *picker, QWinRTFileDialogHelper *helper Q_ASSERT(picker); Q_ASSERT(helper); HRESULT hr; -#ifdef Q_OS_WINPHONE - hr = QEventDispatcherWinRT::runOnXamlThread([picker]() { - HRESULT hr; - ComPtr<IFileSavePicker2> picker2; - hr = picker->QueryInterface(IID_PPV_ARGS(picker2.GetAddressOf())); - RETURN_HR_IF_FAILED("Failed to cast save file picker"); - return picker2->PickSaveFileAndContinue(); - }); - RETURN_FALSE_IF_FAILED("Failed to open single file picker"); - QAbstractEventDispatcher *eventDispatcher = QCoreApplication::eventDispatcher(); - Q_ASSERT(eventDispatcher); - eventDispatcher->installEventFilter(helper); -#else hr = QEventDispatcherWinRT::runOnXamlThread([picker, helper]() { HRESULT hr; ComPtr<IAsyncOperation<StorageFile *>> op; @@ -321,7 +264,6 @@ static bool pickSaveFile(IFileSavePicker *picker, QWinRTFileDialogHelper *helper RETURN_HR_IF_FAILED("Failed to attach save file picker callback"); return S_OK; }); -#endif return SUCCEEDED(hr); } @@ -488,68 +430,6 @@ void QWinRTFileDialogHelper::hide() d->shown = false; } -#ifdef Q_OS_WINPHONE -bool QWinRTFileDialogHelper::eventFilter(QObject *, QEvent *e) -{ - if (e->type() != QEvent::WinEventAct) - return false; - - HRESULT hr; - QActivationEvent *event = static_cast<QActivationEvent *>(e); - ComPtr<IInspectable> inspectable = event->args(); - ComPtr<IActivatedEventArgs> arguments; - hr = inspectable.As(&arguments); - Q_ASSERT_SUCCEEDED(hr); - - ActivationKind activationKind; - hr = arguments->get_Kind(&activationKind); - Q_ASSERT_SUCCEEDED(hr); - - // Handle only File, Folder and Save file pick continuation here. - if (activationKind != ActivationKind_PickFileContinuation - && activationKind != ActivationKind_PickFolderContinuation - && activationKind != ActivationKind_PickSaveFileContinuation) { - return false; - } - - QAbstractEventDispatcher *eventDispatcher = QCoreApplication::eventDispatcher(); - Q_ASSERT(eventDispatcher); - eventDispatcher->removeEventFilter(this); - e->accept(); - - if (activationKind == ActivationKind_PickFileContinuation) { - ComPtr<IFileOpenPickerContinuationEventArgs> fileContinuationArgs; - hr = arguments.As(&fileContinuationArgs); - Q_ASSERT_SUCCEEDED(hr); - ComPtr<IVectorView<StorageFile *>> files; - hr = fileContinuationArgs->get_Files(&files); - Q_ASSERT_SUCCEEDED(hr); - hr = onFilesPicked(files.Get()); - Q_ASSERT_SUCCEEDED(hr); - } else if (activationKind == ActivationKind_PickFolderContinuation) { - ComPtr<IFolderPickerContinuationEventArgs> folderContinuationArgs; - hr = arguments.As(&folderContinuationArgs); - Q_ASSERT_SUCCEEDED(hr); - ComPtr<IStorageFolder> folder; - hr = folderContinuationArgs->get_Folder(&folder); - Q_ASSERT_SUCCEEDED(hr); - hr = onFolderPicked(folder.Get()); - Q_ASSERT_SUCCEEDED(hr); - } else { - ComPtr<IFileSavePickerContinuationEventArgs> saveFileContinuationArgs; - hr = arguments.As(&saveFileContinuationArgs); - Q_ASSERT_SUCCEEDED(hr); - ComPtr<IStorageFile> file; - hr = saveFileContinuationArgs->get_File(&file); - Q_ASSERT_SUCCEEDED(hr); - hr = onFilePicked(file.Get()); - Q_ASSERT_SUCCEEDED(hr); - } - - return true; -} -#endif - void QWinRTFileDialogHelper::setDirectory(const QUrl &directory) { Q_D(QWinRTFileDialogHelper); @@ -586,7 +466,6 @@ QString QWinRTFileDialogHelper::selectedNameFilter() const return d->selectedNameFilter; } -#ifndef Q_OS_WINPHONE HRESULT QWinRTFileDialogHelper::onSingleFilePicked(IAsyncOperation<StorageFile *> *args, AsyncStatus status) { Q_D(QWinRTFileDialogHelper); @@ -643,17 +522,9 @@ HRESULT QWinRTFileDialogHelper::onSingleFolderPicked(IAsyncOperation<StorageFold Q_ASSERT_SUCCEEDED(hr); return onFolderPicked(folder.Get()); } -#endif //Q_OS_WINPHONE HRESULT QWinRTFileDialogHelper::onFilesPicked(IVectorView<StorageFile *> *files) { -#ifdef Q_OS_WINPHONE - Q_D(QWinRTFileDialogHelper); - QEventLoopLocker locker(&d->loop); - d->shown = false; - d->selectedFiles.clear(); -#endif - HRESULT hr; quint32 size; hr = files->get_Size(&size); @@ -676,13 +547,6 @@ HRESULT QWinRTFileDialogHelper::onFilesPicked(IVectorView<StorageFile *> *files) HRESULT QWinRTFileDialogHelper::onFolderPicked(IStorageFolder *folder) { -#ifdef Q_OS_WINPHONE - Q_D(QWinRTFileDialogHelper); - QEventLoopLocker locker(&d->loop); - d->shown = false; - d->selectedFiles.clear(); -#endif - if (!folder) { emit reject(); return S_OK; @@ -695,13 +559,6 @@ HRESULT QWinRTFileDialogHelper::onFolderPicked(IStorageFolder *folder) HRESULT QWinRTFileDialogHelper::onFilePicked(IStorageFile *file) { -#ifdef Q_OS_WINPHONE - Q_D(QWinRTFileDialogHelper); - QEventLoopLocker locker(&d->loop); - d->shown = false; - d->selectedFiles.clear(); -#endif - if (!file) { emit reject(); return S_OK; diff --git a/src/plugins/platforms/winrt/qwinrtfiledialoghelper.h b/src/plugins/platforms/winrt/qwinrtfiledialoghelper.h index 413dee7459..99239aad3a 100644 --- a/src/plugins/platforms/winrt/qwinrtfiledialoghelper.h +++ b/src/plugins/platforms/winrt/qwinrtfiledialoghelper.h @@ -75,9 +75,6 @@ public: void exec() override; bool show(Qt::WindowFlags, Qt::WindowModality, QWindow *) override; void hide() override; -#ifdef Q_OS_WINPHONE - bool eventFilter(QObject *o, QEvent *e) override; -#endif bool defaultNameFilterDisables() const override { return false; } void setDirectory(const QUrl &directory) override; @@ -88,14 +85,12 @@ public: void selectNameFilter(const QString &selectedNameFilter) override; QString selectedNameFilter() const override; -#ifndef Q_OS_WINPHONE HRESULT onSingleFilePicked(ABI::Windows::Foundation::IAsyncOperation<ABI::Windows::Storage::StorageFile *> *, ABI::Windows::Foundation::AsyncStatus); HRESULT onMultipleFilesPicked(ABI::Windows::Foundation::IAsyncOperation<ABI::Windows::Foundation::Collections::IVectorView<ABI::Windows::Storage::StorageFile *> *> *, ABI::Windows::Foundation::AsyncStatus); HRESULT onSingleFolderPicked(ABI::Windows::Foundation::IAsyncOperation<ABI::Windows::Storage::StorageFolder *> *, ABI::Windows::Foundation::AsyncStatus); -#endif private: HRESULT onFilesPicked(ABI::Windows::Foundation::Collections::IVectorView<ABI::Windows::Storage::StorageFile *> *files); diff --git a/src/plugins/platforms/winrt/qwinrtfileengine.cpp b/src/plugins/platforms/winrt/qwinrtfileengine.cpp index 557c13cf63..dab2482ab3 100644 --- a/src/plugins/platforms/winrt/qwinrtfileengine.cpp +++ b/src/plugins/platforms/winrt/qwinrtfileengine.cpp @@ -153,7 +153,6 @@ static HRESULT getDestinationFolder(const QString &fileName, const QString &newF HRESULT hr; ComPtr<IAsyncOperation<StorageFolder *>> op; QFileInfo newFileInfo(newFileName); -#ifndef Q_OS_WINPHONE QFileInfo fileInfo(fileName); if (fileInfo.dir() == newFileInfo.dir()) { ComPtr<IStorageItem2> item; @@ -161,12 +160,7 @@ static HRESULT getDestinationFolder(const QString &fileName, const QString &newF Q_ASSERT_SUCCEEDED(hr); hr = item->GetParentAsync(&op); - } else -#else - Q_UNUSED(fileName); - Q_UNUSED(file) -#endif - { + } else { ComPtr<IStorageFolderStatics> folderFactory; hr = RoGetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Storage_StorageFolder).Get(), IID_PPV_ARGS(&folderFactory)); diff --git a/src/plugins/platforms/winrt/qwinrtintegration.cpp b/src/plugins/platforms/winrt/qwinrtintegration.cpp index ffc3bbf077..7a30c8d98b 100644 --- a/src/plugins/platforms/winrt/qwinrtintegration.cpp +++ b/src/plugins/platforms/winrt/qwinrtintegration.cpp @@ -74,10 +74,8 @@ #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_PHONE_APP) # include <windows.phone.ui.input.h> -# if _MSC_VER >= 1900 -# include <windows.foundation.metadata.h> - using namespace ABI::Windows::Foundation::Metadata; -# endif +# include <windows.foundation.metadata.h> + using namespace ABI::Windows::Foundation::Metadata; #endif @@ -153,7 +151,6 @@ QWinRTIntegration::QWinRTIntegration() : d_ptr(new QWinRTIntegrationPrivate) Q_ASSERT_SUCCEEDED(hr); #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_PHONE_APP) -#if _MSC_VER >= 1900 d->hasHardwareButtons = false; ComPtr<IApiInformationStatics> apiInformationStatics; hr = RoGetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Foundation_Metadata_ApiInformation).Get(), @@ -163,9 +160,6 @@ QWinRTIntegration::QWinRTIntegration() : d_ptr(new QWinRTIntegrationPrivate) const HStringReference valueRef(L"Windows.Phone.UI.Input.HardwareButtons"); hr = apiInformationStatics->IsTypePresent(valueRef.Get(), &d->hasHardwareButtons); } -#else - d->hasHardwareButtons = true; -#endif // _MSC_VER >= 1900 if (d->hasHardwareButtons) { hr = RoGetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Phone_UI_Input_HardwareButtons).Get(), @@ -226,12 +220,11 @@ QWinRTIntegration::~QWinRTIntegration() // Do not execute this on Windows Phone as the application is already // shutting down and trying to unregister suspending/resume handler will // cause exceptions and assert in debug mode -#ifndef Q_OS_WINPHONE for (QHash<CoreApplicationCallbackRemover, EventRegistrationToken>::const_iterator i = d->applicationTokens.begin(); i != d->applicationTokens.end(); ++i) { hr = (d->application.Get()->*i.key())(i.value()); Q_ASSERT_SUCCEEDED(hr); } -#endif + destroyScreen(d->mainScreen); Windows::Foundation::Uninitialize(); } @@ -318,11 +311,7 @@ QPlatformClipboard *QWinRTIntegration::clipboard() const #ifndef QT_NO_DRAGANDDROP QPlatformDrag *QWinRTIntegration::drag() const { -#if _MSC_VER >= 1900 return QWinRTDrag::instance(); -#else - return QPlatformIntegration::drag(); -#endif } #endif // QT_NO_DRAGANDDROP diff --git a/src/plugins/platforms/winrt/qwinrtscreen.cpp b/src/plugins/platforms/winrt/qwinrtscreen.cpp index 2a4b6c8907..150fc8a25e 100644 --- a/src/plugins/platforms/winrt/qwinrtscreen.cpp +++ b/src/plugins/platforms/winrt/qwinrtscreen.cpp @@ -58,7 +58,7 @@ #include <functional> #include <wrl.h> #include <windows.system.h> -#include <Windows.Applicationmodel.h> +#include <Windows.ApplicationModel.h> #include <Windows.ApplicationModel.core.h> #include <windows.devices.input.h> #include <windows.ui.h> @@ -562,7 +562,7 @@ QWinRTScreen::QWinRTScreen() ComPtr<Xaml::IUIElement> uiElement; hr = canvas.As(&uiElement); Q_ASSERT_SUCCEEDED(hr); -#if _MSC_VER >= 1900 && !defined(QT_NO_DRAGANDDROP) +#ifndef QT_NO_DRAGANDDROP QWinRTDrag::instance()->setUiElement(uiElement); #endif hr = window->put_Content(uiElement.Get()); @@ -833,7 +833,7 @@ void QWinRTScreen::addWindow(QWindow *window) handleExpose(); QWindowSystemInterface::flushWindowSystemEvents(QEventLoop::ExcludeUserInputEvents); -#if _MSC_VER >= 1900 && !defined(QT_NO_DRAGANDDROP) +#ifndef QT_NO_DRAGANDDROP QWinRTDrag::instance()->setDropTarget(window); #endif } @@ -852,7 +852,7 @@ void QWinRTScreen::removeWindow(QWindow *window) QWindowSystemInterface::handleWindowActivated(Q_NULLPTR, Qt::OtherFocusReason); handleExpose(); QWindowSystemInterface::flushWindowSystemEvents(QEventLoop::ExcludeUserInputEvents); -#if _MSC_VER >= 1900 && !defined(QT_NO_DRAGANDDROP) +#ifndef QT_NO_DRAGANDDROP if (wasTopWindow) QWinRTDrag::instance()->setDropTarget(topWindow()); #endif @@ -1221,11 +1221,7 @@ HRESULT QWinRTScreen::onPointerUpdated(ICoreWindow *, IPointerEventArgs *args) properties->get_Pressure(&pressure); boolean isPressed; -#ifndef Q_OS_WINPHONE pointerPoint->get_IsInContact(&isPressed); -#else - properties->get_IsLeftButtonPressed(&isPressed); // IsInContact not reliable on phone -#endif // Devices like the Hololens set a static pressure of 0.5 independent // of the pressed state. In those cases we need to synthesize the @@ -1356,16 +1352,10 @@ HRESULT QWinRTScreen::onDpiChanged(IDisplayInformation *, IInspectable *) Q_D(QWinRTScreen); HRESULT hr; -#ifdef Q_OS_WINPHONE - ComPtr<IDisplayInformation2> displayInformation; - hr = d->displayInformation.As(&displayInformation); - RETURN_OK_IF_FAILED("Failed to cast display information."); - hr = displayInformation->get_RawPixelsPerViewPixel(&d->scaleFactor); -#else ResolutionScale resolutionScale; hr = d->displayInformation->get_ResolutionScale(&resolutionScale); d->scaleFactor = qreal(resolutionScale) / 100; -#endif + qCDebug(lcQpaWindows) << __FUNCTION__ << "Scale Factor:" << d->scaleFactor; RETURN_OK_IF_FAILED("Failed to get scale factor"); diff --git a/src/plugins/platforms/winrt/qwinrttheme.cpp b/src/plugins/platforms/winrt/qwinrttheme.cpp index f84688f045..6b35bde83e 100644 --- a/src/plugins/platforms/winrt/qwinrttheme.cpp +++ b/src/plugins/platforms/winrt/qwinrttheme.cpp @@ -84,7 +84,6 @@ static inline QColor fromColor(const Color &color) return QColor(color.R, color.G, color.B, color.A); } -#if _MSC_VER >= 1900 static bool uiColorSettings(const wchar_t *value, UIElementType type, Color *color) { static ComPtr<IApiInformationStatics> apiInformationStatics; @@ -189,103 +188,6 @@ static void nativeColorSettings(QPalette &p) p.setColor(QPalette::BrightText, fromColor(color)); } -#else // _MSC_VER >= 1900 - -static void nativeColorSettings(QPalette &p) -{ - HRESULT hr; - Color color; - -#ifdef Q_OS_WINPHONE - hr = uiSettings()->UIElementColor(UIElementType_PopupBackground, &color); - Q_ASSERT_SUCCEEDED(hr); - p.setColor(QPalette::ToolTipBase, fromColor(color)); - p.setColor(QPalette::AlternateBase, fromColor(color)); - - hr = uiSettings()->UIElementColor(UIElementType_NonTextMedium, &color); - Q_ASSERT_SUCCEEDED(hr); - p.setColor(QPalette::Button, fromColor(color)); - hr = uiSettings()->UIElementColor(UIElementType_NonTextMediumHigh, &color); - Q_ASSERT_SUCCEEDED(hr); - p.setColor(QPalette::Midlight, fromColor(color)); - hr = uiSettings()->UIElementColor(UIElementType_NonTextHigh, &color); - Q_ASSERT_SUCCEEDED(hr); - p.setColor(QPalette::Light, fromColor(color)); - hr = uiSettings()->UIElementColor(UIElementType_NonTextMediumLow, &color); - Q_ASSERT_SUCCEEDED(hr); - p.setColor(QPalette::Mid, fromColor(color)); - hr = uiSettings()->UIElementColor(UIElementType_NonTextLow, &color); - Q_ASSERT_SUCCEEDED(hr); - p.setColor(QPalette::Dark, fromColor(color)); - - hr = uiSettings()->UIElementColor(UIElementType_TextHigh, &color); - Q_ASSERT_SUCCEEDED(hr); - p.setColor(QPalette::ButtonText, fromColor(color)); - p.setColor(QPalette::Text, fromColor(color)); - p.setColor(QPalette::WindowText, fromColor(color)); - - hr = uiSettings()->UIElementColor(UIElementType_TextMedium, &color); - Q_ASSERT_SUCCEEDED(hr); - p.setColor(QPalette::ToolTipText, fromColor(color)); - - hr = uiSettings()->UIElementColor(UIElementType_AccentColor, &color); - Q_ASSERT_SUCCEEDED(hr); - p.setColor(QPalette::Highlight, fromColor(color)); - - hr = uiSettings()->UIElementColor(UIElementType_PageBackground, &color); - Q_ASSERT_SUCCEEDED(hr); - p.setColor(QPalette::Window, fromColor(color)); - p.setColor(QPalette::Base, fromColor(color)); - - hr = uiSettings()->UIElementColor(UIElementType_TextContrastWithHigh, &color); - Q_ASSERT_SUCCEEDED(hr); - p.setColor(QPalette::BrightText, fromColor(color)); -#else - hr = uiSettings()->UIElementColor(UIElementType_ActiveCaption, &color); - Q_ASSERT_SUCCEEDED(hr); - p.setColor(QPalette::ToolTipBase, fromColor(color)); - - hr = uiSettings()->UIElementColor(UIElementType_Background, &color); - Q_ASSERT_SUCCEEDED(hr); - p.setColor(QPalette::AlternateBase, fromColor(color)); - - hr = uiSettings()->UIElementColor(UIElementType_ButtonFace, &color); - Q_ASSERT_SUCCEEDED(hr); - p.setColor(QPalette::Button, fromColor(color)); - p.setColor(QPalette::Midlight, fromColor(color).lighter(110)); - p.setColor(QPalette::Light, fromColor(color).lighter(150)); - p.setColor(QPalette::Mid, fromColor(color).dark(130)); - p.setColor(QPalette::Dark, fromColor(color).dark(150)); - - hr = uiSettings()->UIElementColor(UIElementType_ButtonText, &color); - Q_ASSERT_SUCCEEDED(hr); - p.setColor(QPalette::ButtonText, fromColor(color)); - p.setColor(QPalette::Text, fromColor(color)); - - hr = uiSettings()->UIElementColor(UIElementType_CaptionText, &color); - Q_ASSERT_SUCCEEDED(hr); - p.setColor(QPalette::ToolTipText, fromColor(color)); - - hr = uiSettings()->UIElementColor(UIElementType_Highlight, &color); - Q_ASSERT_SUCCEEDED(hr); - p.setColor(QPalette::Highlight, fromColor(color)); - - hr = uiSettings()->UIElementColor(UIElementType_HighlightText, &color); - Q_ASSERT_SUCCEEDED(hr); - p.setColor(QPalette::HighlightedText, fromColor(color)); - - hr = uiSettings()->UIElementColor(UIElementType_Window, &color); - Q_ASSERT_SUCCEEDED(hr); - p.setColor(QPalette::Window, fromColor(color)); - p.setColor(QPalette::Base, fromColor(color)); - - hr = uiSettings()->UIElementColor(UIElementType_Hotlight, &color); - Q_ASSERT_SUCCEEDED(hr); - p.setColor(QPalette::BrightText, fromColor(color)); -#endif -} -#endif // _MSC_VER < 1900 - QWinRTTheme::QWinRTTheme() : d_ptr(new QWinRTThemePrivate) { diff --git a/src/plugins/platforms/winrt/qwinrtwindow.cpp b/src/plugins/platforms/winrt/qwinrtwindow.cpp index 8f3b86ff3b..c40a1b8c45 100644 --- a/src/plugins/platforms/winrt/qwinrtwindow.cpp +++ b/src/plugins/platforms/winrt/qwinrtwindow.cpp @@ -331,7 +331,6 @@ void QWinRTWindow::setWindowState(Qt::WindowState state) if (d->state == state) return; -#if _MSC_VER >= 1900 if (state == Qt::WindowFullScreen) { HRESULT hr; boolean success; @@ -378,7 +377,6 @@ void QWinRTWindow::setWindowState(Qt::WindowState state) return; } } -#endif // _MSC_VER >= 1900 if (state == Qt::WindowMinimized) setUIElementVisibility(d->uiElement.Get(), false); diff --git a/src/plugins/platforms/winrt/winrt.pro b/src/plugins/platforms/winrt/winrt.pro index be2f5ca7e2..35801fdacc 100644 --- a/src/plugins/platforms/winrt/winrt.pro +++ b/src/plugins/platforms/winrt/winrt.pro @@ -52,7 +52,7 @@ WINRT_SDK_VERSION_STRING = $$(UCRTVersion) WINRT_SDK_VERSION = $$member($$list($$split(WINRT_SDK_VERSION_STRING, .)), 2) lessThan(WINRT_SDK_VERSION, 14322): DEFINES += QT_WINRT_LIMITED_DRAGANDDROP -*-msvc2013|contains(DEFINES, QT_NO_DRAGANDDROP) { +contains(DEFINES, QT_NO_DRAGANDDROP) { SOURCES -= qwinrtdrag.cpp HEADERS -= qwinrtdrag.h } diff --git a/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qglxintegration.cpp b/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qglxintegration.cpp index 4e0c73450e..caa4b7361a 100644 --- a/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qglxintegration.cpp +++ b/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qglxintegration.cpp @@ -56,6 +56,8 @@ #include <QtGlxSupport/private/qglxconvenience_p.h> #include <QtPlatformHeaders/QGLXNativeContext> +#include "qxcbglintegration.h" + #if !defined(QT_STATIC) && QT_CONFIG(dlopen) #include <dlfcn.h> #endif @@ -691,6 +693,10 @@ void QGLXContext::queryDummyContext() if (const char *renderer = (const char *) glGetString(GL_RENDERER)) { for (int i = 0; qglx_threadedgl_blacklist_renderer[i]; ++i) { if (strstr(renderer, qglx_threadedgl_blacklist_renderer[i]) != 0) { + qCInfo(lcQpaGl).nospace() << "Multithreaded OpenGL disabled: " + "blacklisted renderer \"" + << qglx_threadedgl_blacklist_renderer[i] + << "\""; m_supportsThreading = false; break; } @@ -700,6 +706,11 @@ void QGLXContext::queryDummyContext() if (glxvendor) { for (int i = 0; qglx_threadedgl_blacklist_vendor[i]; ++i) { if (strstr(glxvendor, qglx_threadedgl_blacklist_vendor[i]) != 0) { + qCInfo(lcQpaGl).nospace() << "Multithreaded OpenGL disabled: " + "blacklisted vendor \"" + << qglx_threadedgl_blacklist_vendor[i] + << "\""; + m_supportsThreading = false; break; } @@ -709,6 +720,11 @@ void QGLXContext::queryDummyContext() context.doneCurrent(); if (oldContext && oldSurface) oldContext->makeCurrent(oldSurface); + + if (!m_supportsThreading) { + qCInfo(lcQpaGl) << "Force-enable multithreaded OpenGL by setting " + "environment variable QT_OPENGL_NO_SANITY_CHECK"; + } } bool QGLXContext::supportsThreading() diff --git a/src/plugins/platforms/xcb/qxcbclipboard.cpp b/src/plugins/platforms/xcb/qxcbclipboard.cpp index a293066b93..01b3bca0d2 100644 --- a/src/plugins/platforms/xcb/qxcbclipboard.cpp +++ b/src/plugins/platforms/xcb/qxcbclipboard.cpp @@ -267,11 +267,6 @@ const int QXcbClipboard::clipboard_timeout = 5000; QXcbClipboard::QXcbClipboard(QXcbConnection *c) : QXcbObject(c), QPlatformClipboard() - , m_requestor(XCB_NONE) - , m_owner(XCB_NONE) - , m_incr_active(false) - , m_clipboard_closing(false) - , m_incr_receive_time(0) { Q_ASSERT(QClipboard::Clipboard == 0); Q_ASSERT(QClipboard::Selection == 1); diff --git a/src/plugins/platforms/xcb/qxcbclipboard.h b/src/plugins/platforms/xcb/qxcbclipboard.h index a0a4f4e5a1..bfeae13e10 100644 --- a/src/plugins/platforms/xcb/qxcbclipboard.h +++ b/src/plugins/platforms/xcb/qxcbclipboard.h @@ -102,14 +102,14 @@ private: QMimeData *m_clientClipboard[2]; xcb_timestamp_t m_timestamp[2]; - xcb_window_t m_requestor; - xcb_window_t m_owner; + xcb_window_t m_requestor = XCB_NONE; + xcb_window_t m_owner = XCB_NONE; static const int clipboard_timeout; - bool m_incr_active; - bool m_clipboard_closing; - xcb_timestamp_t m_incr_receive_time; + bool m_incr_active = false; + bool m_clipboard_closing = false; + xcb_timestamp_t m_incr_receive_time = 0; }; #endif // QT_NO_CLIPBOARD diff --git a/src/plugins/platforms/xcb/qxcbconnection.cpp b/src/plugins/platforms/xcb/qxcbconnection.cpp index 5e600c740b..8c5f8cae08 100644 --- a/src/plugins/platforms/xcb/qxcbconnection.cpp +++ b/src/plugins/platforms/xcb/qxcbconnection.cpp @@ -131,7 +131,7 @@ typedef struct qt_xcb_ge_event_t { static inline bool isXIEvent(xcb_generic_event_t *event, int opCode) { - qt_xcb_ge_event_t *e = (qt_xcb_ge_event_t *)event; + qt_xcb_ge_event_t *e = reinterpret_cast<qt_xcb_ge_event_t *>(event); return e->extension == opCode; } #endif // XCB_USE_XINPUT2 @@ -251,7 +251,7 @@ void QXcbConnection::updateScreens(const xcb_randr_notify_event_t *event) // Find a fake screen const auto scrs = virtualDesktop->screens(); for (QPlatformScreen *scr : scrs) { - QXcbScreen *xcbScreen = (QXcbScreen *)scr; + QXcbScreen *xcbScreen = static_cast<QXcbScreen *>(scr); if (xcbScreen->output() == XCB_NONE) { screen = xcbScreen; break; @@ -377,7 +377,7 @@ void QXcbConnection::destroyScreen(QXcbScreen *screen) // When primary screen is removed, set the new primary screen // which belongs to the primary virtual desktop. if (screen->isPrimary()) { - QXcbScreen *newPrimary = (QXcbScreen *)virtualDesktop->screens().at(0); + QXcbScreen *newPrimary = static_cast<QXcbScreen *>(virtualDesktop->screens().at(0)); newPrimary->setPrimary(true); const int idx = m_screens.indexOf(newPrimary); if (idx > 0) @@ -552,32 +552,10 @@ void QXcbConnection::initializeScreens() } QXcbConnection::QXcbConnection(QXcbNativeInterface *nativeInterface, bool canGrabServer, xcb_visualid_t defaultVisualId, const char *displayName) - : m_connection(0) - , m_canGrabServer(canGrabServer) + : m_canGrabServer(canGrabServer) , m_defaultVisualId(defaultVisualId) - , m_primaryScreenNumber(0) , m_displayName(displayName ? QByteArray(displayName) : qgetenv("DISPLAY")) , m_nativeInterface(nativeInterface) -#ifdef XCB_USE_XLIB - , m_xlib_display(0) -#endif - , xfixes_first_event(0) - , xrandr_first_event(0) - , xkb_first_event(0) - , has_xinerama_extension(false) - , has_shape_extension(false) - , has_randr_extension(false) - , has_input_shape(false) - , has_xkb(false) - , m_buttons(0) - , m_focusWindow(0) - , m_mouseGrabber(0) - , m_mousePressWindow(0) - , m_clientLeader(0) - , m_systemTrayTracker(0) - , m_glIntegration(Q_NULLPTR) - , m_xiGrab(false) - , m_qtSelectionOwner(0) { #ifdef XCB_USE_XLIB Display *dpy = XOpenDisplay(m_displayName.constData()); @@ -618,9 +596,6 @@ QXcbConnection::QXcbConnection(QXcbNativeInterface *nativeInterface, bool canGra initializeAllAtoms(); - m_time = XCB_CURRENT_TIME; - m_netWmUserTime = XCB_CURRENT_TIME; - if (!qEnvironmentVariableIsSet("QT_XCB_NO_XRANDR")) initializeXRandr(); if (!has_randr_extension) @@ -630,7 +605,6 @@ QXcbConnection::QXcbConnection(QXcbNativeInterface *nativeInterface, bool canGra initializeXRender(); #if defined(XCB_USE_XINPUT2) - m_xi2Enabled = false; if (!qEnvironmentVariableIsSet("QT_XCB_NO_XI2")) initializeXInput2(); #endif @@ -712,7 +686,7 @@ QXcbConnection::~QXcbConnection() delete m_glIntegration; #ifdef XCB_USE_XLIB - XCloseDisplay((Display *)m_xlib_display); + XCloseDisplay(static_cast<Display *>(m_xlib_display)); #else xcb_disconnect(xcb_connection()); #endif @@ -755,7 +729,7 @@ QXcbWindow *QXcbConnection::platformWindowFromId(xcb_window_t id) #define HANDLE_PLATFORM_WINDOW_EVENT(event_t, windowMember, handler) \ { \ - event_t *e = (event_t *)event; \ + event_t *e = reinterpret_cast<event_t *>(event); \ if (QXcbWindowEventListener *eventListener = windowEventListenerFromId(e->windowMember)) { \ handled = eventListener->handleGenericEvent(event, &result); \ if (!handled) \ @@ -766,7 +740,7 @@ break; #define HANDLE_KEYBOARD_EVENT(event_t, handler) \ { \ - event_t *e = (event_t *)event; \ + event_t *e = reinterpret_cast<event_t *>(event); \ if (QXcbWindowEventListener *eventListener = windowEventListenerFromId(e->event)) { \ handled = eventListener->handleGenericEvent(event, &result); \ if (!handled) \ @@ -1185,11 +1159,11 @@ void QXcbConnection::handleXcbEvent(xcb_generic_event_t *event) m_keyboard->updateXKBStateFromCore(((xcb_key_release_event_t *)event)->state); HANDLE_KEYBOARD_EVENT(xcb_key_release_event_t, handleKeyReleaseEvent); case XCB_MAPPING_NOTIFY: - m_keyboard->handleMappingNotifyEvent((xcb_mapping_notify_event_t *)event); + m_keyboard->handleMappingNotifyEvent(reinterpret_cast<xcb_mapping_notify_event_t *>(event)); break; case XCB_SELECTION_REQUEST: { - xcb_selection_request_event_t *sr = (xcb_selection_request_event_t *)event; + xcb_selection_request_event_t *sr = reinterpret_cast<xcb_selection_request_event_t *>(event); #ifndef QT_NO_DRAGANDDROP if (sr->selection == atom(QXcbAtom::XdndSelection)) m_drag->handleSelectionRequest(sr); @@ -1203,19 +1177,19 @@ void QXcbConnection::handleXcbEvent(xcb_generic_event_t *event) break; } case XCB_SELECTION_CLEAR: - setTime(((xcb_selection_clear_event_t *)event)->time); + setTime((reinterpret_cast<xcb_selection_clear_event_t *>(event))->time); #ifndef QT_NO_CLIPBOARD - m_clipboard->handleSelectionClearRequest((xcb_selection_clear_event_t *)event); + m_clipboard->handleSelectionClearRequest(reinterpret_cast<xcb_selection_clear_event_t *>(event)); #endif handled = true; break; case XCB_SELECTION_NOTIFY: - setTime(((xcb_selection_notify_event_t *)event)->time); + setTime((reinterpret_cast<xcb_selection_notify_event_t *>(event))->time); handled = false; break; case XCB_PROPERTY_NOTIFY: { - xcb_property_notify_event_t *pn = (xcb_property_notify_event_t *)event; + xcb_property_notify_event_t *pn = reinterpret_cast<xcb_property_notify_event_t *>(event); if (pn->atom == atom(QXcbAtom::_NET_WORKAREA)) { QXcbVirtualDesktop *virtualDesktop = virtualDesktopForRootWindow(pn->window); if (virtualDesktop) @@ -1240,7 +1214,7 @@ void QXcbConnection::handleXcbEvent(xcb_generic_event_t *event) if (!handled) { if (response_type == xfixes_first_event + XCB_XFIXES_SELECTION_NOTIFY) { - xcb_xfixes_selection_notify_event_t *notify_event = (xcb_xfixes_selection_notify_event_t *)event; + xcb_xfixes_selection_notify_event_t *notify_event = reinterpret_cast<xcb_xfixes_selection_notify_event_t *>(event); setTime(notify_event->timestamp); #ifndef QT_NO_CLIPBOARD m_clipboard->handleXFixesSelectionRequest(notify_event); @@ -1250,10 +1224,10 @@ void QXcbConnection::handleXcbEvent(xcb_generic_event_t *event) handled = true; } else if (has_randr_extension && response_type == xrandr_first_event + XCB_RANDR_NOTIFY) { - updateScreens((xcb_randr_notify_event_t *)event); + updateScreens(reinterpret_cast<xcb_randr_notify_event_t *>(event)); handled = true; } else if (has_randr_extension && response_type == xrandr_first_event + XCB_RANDR_SCREEN_CHANGE_NOTIFY) { - xcb_randr_screen_change_notify_event_t *change_event = (xcb_randr_screen_change_notify_event_t *)event; + xcb_randr_screen_change_notify_event_t *change_event = reinterpret_cast<xcb_randr_screen_change_notify_event_t *>(event); for (QXcbScreen *s : qAsConst(m_screens)) { if (s->root() == change_event->root ) s->handleScreenChange(change_event); @@ -1362,7 +1336,7 @@ void QXcbEventReader::run() void QXcbEventReader::addEvent(xcb_generic_event_t *event) { if ((event->response_type & ~0x80) == XCB_CLIENT_MESSAGE - && ((xcb_client_message_event_t *)event)->type == m_connection->atom(QXcbAtom::_QT_CLOSE_CONNECTION)) + && (reinterpret_cast<xcb_client_message_event_t *>(event))->type == m_connection->atom(QXcbAtom::_QT_CLOSE_CONNECTION)) m_connection = 0; m_events << event; } @@ -1428,7 +1402,7 @@ void QXcbConnection::sendConnectionEvent(QXcbAtom::Atom a, uint id) event.type = atom(a); event.data.data32[0] = id; - Q_XCB_CALL(xcb_send_event(xcb_connection(), false, eventListener, XCB_EVENT_MASK_NO_EVENT, (const char *)&event)); + Q_XCB_CALL(xcb_send_event(xcb_connection(), false, eventListener, XCB_EVENT_MASK_NO_EVENT, reinterpret_cast<const char *>(&event))); Q_XCB_CALL(xcb_destroy_window(m_connection, eventListener)); xcb_flush(xcb_connection()); } @@ -1448,7 +1422,7 @@ namespace if ((event->response_type & ~0x80) != type) { return false; } else { - xcb_property_notify_event_t *pn = (xcb_property_notify_event_t *)event; + xcb_property_notify_event_t *pn = reinterpret_cast<xcb_property_notify_event_t *>(event); if ((pn->window == window) && (pn->atom == atom)) return true; } @@ -1476,7 +1450,7 @@ xcb_timestamp_t QXcbConnection::getTimestamp() event = checkEvent(checker); } - xcb_property_notify_event_t *pn = (xcb_property_notify_event_t *)event; + xcb_property_notify_event_t *pn = reinterpret_cast<xcb_property_notify_event_t *>(event); xcb_timestamp_t timestamp = pn->time; free(event); @@ -1500,7 +1474,8 @@ xcb_window_t QXcbConnection::getQtSelectionOwner() { if (!m_qtSelectionOwner) { xcb_screen_t *xcbScreen = primaryVirtualDesktop()->screen(); - int x = 0, y = 0, w = 3, h = 3; + int16_t x = 0, y = 0; + uint16_t w = 3, h = 3; m_qtSelectionOwner = xcb_generate_id(xcb_connection()); Q_XCB_CALL(xcb_create_window(xcb_connection(), XCB_COPY_FROM_PARENT, // depth -- same as root @@ -1689,7 +1664,7 @@ bool QXcbConnection::compressEvent(xcb_generic_event_t *event, int currentIndex, for (int j = nextIndex; j < eventqueue->size(); ++j) { xcb_generic_event_t *next = eventqueue->at(j); if (isValid(next) && next->response_type == XCB_CONFIGURE_NOTIFY - && ((xcb_configure_notify_event_t *)next)->event == ((xcb_configure_notify_event_t*)event)->event) + && reinterpret_cast<xcb_configure_notify_event_t *>(next)->event == reinterpret_cast<xcb_configure_notify_event_t *>(event)->event) { return true; } @@ -1718,7 +1693,7 @@ void QXcbConnection::processXcbEvents() (*eventqueue)[i] = 0; if (!(event->response_type & ~0x80)) { - handleXcbError((xcb_generic_error_t *)event); + handleXcbError(reinterpret_cast<xcb_generic_error_t *>(event)); continue; } diff --git a/src/plugins/platforms/xcb/qxcbconnection.h b/src/plugins/platforms/xcb/qxcbconnection.h index 01a97a187a..ffd0c87a3e 100644 --- a/src/plugins/platforms/xcb/qxcbconnection.h +++ b/src/plugins/platforms/xcb/qxcbconnection.h @@ -551,10 +551,9 @@ private: void destroyScreen(QXcbScreen *screen); void initializeScreens(); bool compressEvent(xcb_generic_event_t *event, int currentIndex, QXcbEventArray *eventqueue) const; - #ifdef XCB_USE_XINPUT2 - bool m_xi2Enabled; - int m_xi2Minor; + bool m_xi2Enabled = false; + int m_xi2Minor = 2; void initializeXInput2(); void finalizeXInput2(); void xi2SetupDevices(); @@ -568,20 +567,17 @@ private: #endif // XCB_USE_XINPUT22 #ifndef QT_NO_TABLETEVENT struct TabletData { - TabletData() : deviceId(0), pointerType(QTabletEvent::UnknownPointer), - tool(QTabletEvent::Stylus), buttons(0), serialId(0), inProximity(false) { } - int deviceId; - QTabletEvent::PointerType pointerType; - QTabletEvent::TabletDevice tool; - Qt::MouseButtons buttons; - qint64 serialId; - bool inProximity; + int deviceId = 0; + QTabletEvent::PointerType pointerType = QTabletEvent::UnknownPointer; + QTabletEvent::TabletDevice tool = QTabletEvent::Stylus; + Qt::MouseButtons buttons = 0; + qint64 serialId = 0; + bool inProximity = false; struct ValuatorClassInfo { - ValuatorClassInfo() : minVal(0.), maxVal(0.), curVal(0.) { } - double minVal; - double maxVal; - double curVal; - int number; + double minVal = 0; + double maxVal = 0; + double curVal = 0; + int number = -1; }; QHash<int, ValuatorClassInfo> valuatorInfo; }; @@ -593,12 +589,13 @@ private: TabletData *tabletDataForDevice(int id); #endif // !QT_NO_TABLETEVENT struct ScrollingDevice { - ScrollingDevice() : deviceId(0), verticalIndex(0), horizontalIndex(0), orientations(0), legacyOrientations(0) { } - int deviceId; - int verticalIndex, horizontalIndex; - double verticalIncrement, horizontalIncrement; - Qt::Orientations orientations; - Qt::Orientations legacyOrientations; + int deviceId = 0; + int verticalIndex = 0; + int horizontalIndex = 0; + double verticalIncrement = 0; + double horizontalIncrement = 0; + Qt::Orientations orientations = 0; + Qt::Orientations legacyOrientations = 0; QPointF lastScrollPosition; }; void updateScrollingDevice(ScrollingDevice& scrollingDevice, int num_classes, void *classes); @@ -609,36 +606,36 @@ private: static void xi2PrepareXIGenericDeviceEvent(xcb_ge_event_t *event); #endif - xcb_connection_t *m_connection; - const xcb_setup_t *m_setup; - bool m_canGrabServer; - xcb_visualid_t m_defaultVisualId; + xcb_connection_t *m_connection = nullptr; + const xcb_setup_t *m_setup = nullptr; + const bool m_canGrabServer; + const xcb_visualid_t m_defaultVisualId; QList<QXcbVirtualDesktop *> m_virtualDesktops; QList<QXcbScreen *> m_screens; - int m_primaryScreenNumber; + int m_primaryScreenNumber = 0; xcb_atom_t m_allAtoms[QXcbAtom::NAtoms]; - xcb_timestamp_t m_time; - xcb_timestamp_t m_netWmUserTime; + xcb_timestamp_t m_time = XCB_CURRENT_TIME; + xcb_timestamp_t m_netWmUserTime = XCB_CURRENT_TIME; QByteArray m_displayName; - QXcbKeyboard *m_keyboard; + QXcbKeyboard *m_keyboard = nullptr; #ifndef QT_NO_CLIPBOARD - QXcbClipboard *m_clipboard; + QXcbClipboard *m_clipboard = nullptr; #endif #ifndef QT_NO_DRAGANDDROP - QXcbDrag *m_drag; + QXcbDrag *m_drag = nullptr; #endif QScopedPointer<QXcbWMSupport> m_wmSupport; - QXcbNativeInterface *m_nativeInterface; + QXcbNativeInterface *m_nativeInterface = nullptr; #if defined(XCB_USE_XLIB) - void *m_xlib_display; + void *m_xlib_display = nullptr; #endif - QXcbEventReader *m_reader; + QXcbEventReader *m_reader = nullptr; #if defined(XCB_USE_XINPUT2) QHash<int, XInput2TouchDeviceData*> m_touchDevices; #ifdef XCB_USE_XINPUT22 @@ -671,29 +668,29 @@ private: QVector<PeekFunc> m_peekFuncs; - uint32_t xfixes_first_event; - uint32_t xrandr_first_event; - uint32_t xkb_first_event; + uint32_t xfixes_first_event = 0; + uint32_t xrandr_first_event = 0; + uint32_t xkb_first_event = 0; - bool has_xinerama_extension; - bool has_shape_extension; - bool has_randr_extension; + bool has_xinerama_extension = false; + bool has_shape_extension = false; + bool has_randr_extension = false; bool has_input_shape; - bool has_xkb; + bool has_xkb = false; - Qt::MouseButtons m_buttons; + Qt::MouseButtons m_buttons = 0; - QXcbWindow *m_focusWindow; - QXcbWindow *m_mouseGrabber; - QXcbWindow *m_mousePressWindow; + QXcbWindow *m_focusWindow = nullptr; + QXcbWindow *m_mouseGrabber = nullptr; + QXcbWindow *m_mousePressWindow = nullptr; - xcb_window_t m_clientLeader; + xcb_window_t m_clientLeader = 0; QByteArray m_startupId; - QXcbSystemTrayTracker *m_systemTrayTracker; - QXcbGlIntegration *m_glIntegration; - bool m_xiGrab; + QXcbSystemTrayTracker *m_systemTrayTracker = nullptr; + QXcbGlIntegration *m_glIntegration = nullptr; + bool m_xiGrab = false; - xcb_window_t m_qtSelectionOwner; + xcb_window_t m_qtSelectionOwner = 0; friend class QXcbEventReader; }; @@ -704,7 +701,7 @@ Q_DECLARE_TYPEINFO(QXcbConnection::TabletData, Q_MOVABLE_TYPE); #endif #endif -#define DISPLAY_FROM_XCB(object) ((Display *)(object->connection()->xlib_display())) +#define DISPLAY_FROM_XCB(object) (reinterpret_cast<Display *>(object->connection()->xlib_display())) #define CREATE_VISUALINFO_FROM_DEFAULT_VISUALID(object) ((XVisualInfo *)(object->connection()->createVisualInfoForDefaultVisualId())) template<typename T> diff --git a/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp b/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp index d91cbfe82d..14c138a911 100644 --- a/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp +++ b/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp @@ -42,6 +42,7 @@ #include "qxcbscreen.h" #include "qxcbwindow.h" #include "qtouchdevice.h" +#include "QtCore/qmetaobject.h" #include <qpa/qwindowsysteminterface_p.h> #include <QDebug> #include <cmath> @@ -52,14 +53,8 @@ #include <X11/extensions/XI2proto.h> struct XInput2TouchDeviceData { - XInput2TouchDeviceData() - : xiDeviceInfo(0) - , qtTouchDevice(0) - , providesTouchOrientation(false) - { - } - XIDeviceInfo *xiDeviceInfo; - QTouchDevice *qtTouchDevice; + XIDeviceInfo *xiDeviceInfo = nullptr; + QTouchDevice *qtTouchDevice = nullptr; QHash<int, QWindowSystemInterface::TouchPoint> touchPoints; QHash<int, QPointF> pointPressedPosition; // in screen coordinates where each point was pressed @@ -67,7 +62,7 @@ struct XInput2TouchDeviceData { QPointF firstPressedPosition; // in screen coordinates where the first point was pressed QPointF firstPressedNormalPosition; // device coordinates (0 to 1, 0 to 1) where the first point was pressed QSizeF size; // device size in mm - bool providesTouchOrientation; + bool providesTouchOrientation = false; }; void QXcbConnection::initializeXInput2() @@ -80,7 +75,7 @@ void QXcbConnection::initializeXInput2() Display *xDisplay = static_cast<Display *>(m_xlib_display); if (XQueryExtension(xDisplay, "XInputExtension", &m_xiOpCode, &m_xiEventBase, &m_xiErrorBase)) { int xiMajor = 2; - m_xi2Minor = 2; // try 2.2 first, needed for TouchBegin/Update/End + // try 2.2 first, needed for TouchBegin/Update/End if (XIQueryVersion(xDisplay, &xiMajor, &m_xi2Minor) == BadRequest) { m_xi2Minor = 1; // for smooth scrolling 2.1 is enough if (XIQueryVersion(xDisplay, &xiMajor, &m_xi2Minor) == BadRequest) { @@ -214,6 +209,8 @@ void QXcbConnection::xi2SetupDevices() isTablet = true; tabletData.pointerType = QTabletEvent::Cursor; dbgType = QLatin1String("cursor"); + } else if (name.contains("wacom") && name.contains("finger touch")) { + isTablet = false; } else if ((name.contains("pen") || name.contains("stylus")) && isTablet) { tabletData.pointerType = QTabletEvent::Pen; dbgType = QLatin1String("pen"); @@ -232,6 +229,9 @@ void QXcbConnection::xi2SetupDevices() isTablet = true; tabletData.pointerType = QTabletEvent::Pen; dbgType = QLatin1String("pen"); + } else if (name.contains("uc-logic") && isTablet) { + tabletData.pointerType = QTabletEvent::Pen; + dbgType = QLatin1String("pen"); } else { isTablet = false; } @@ -444,10 +444,10 @@ XInput2TouchDeviceData *QXcbConnection::touchDeviceForId(int id) dev->size.setHeight((vci->max - vci->min) * 1000.0 / vciResolution); } else if (vci->label == atom(QXcbAtom::AbsX)) { caps |= QTouchDevice::Position; - dev->size.setHeight((vci->max - vci->min) * 1000.0 / vciResolution); + dev->size.setWidth((vci->max - vci->min) * 1000.0 / vciResolution); } else if (vci->label == atom(QXcbAtom::AbsY)) { caps |= QTouchDevice::Position; - dev->size.setWidth((vci->max - vci->min) * 1000.0 / vciResolution); + dev->size.setHeight((vci->max - vci->min) * 1000.0 / vciResolution); } break; } @@ -1066,6 +1066,18 @@ static QTabletEvent::TabletDevice toolIdToTabletDevice(quint32 toolId) { return QTabletEvent::Stylus; // Safe default assumption if nonzero } +static const char *toolName(QTabletEvent::TabletDevice tool) { + static const QMetaObject *metaObject = qt_getEnumMetaObject(tool); + static const QMetaEnum me = metaObject->enumerator(metaObject->indexOfEnumerator(qt_getEnumName(tool))); + return me.valueToKey(tool); +} + +static const char *pointerTypeName(QTabletEvent::PointerType ptype) { + static const QMetaObject *metaObject = qt_getEnumMetaObject(ptype); + static const QMetaEnum me = metaObject->enumerator(metaObject->indexOfEnumerator(qt_getEnumName(ptype))); + return me.valueToKey(ptype); +} + bool QXcbConnection::xi2HandleTabletEvent(const void *event, TabletData *tabletData) { bool handled = true; @@ -1087,10 +1099,7 @@ bool QXcbConnection::xi2HandleTabletEvent(const void *event, TabletData *tabletD break; } case XI_Motion: - // Report TabletMove only when the stylus is touching the tablet or any button is pressed. - // TODO: report proximity (hover) motion (no suitable Qt event exists yet). - if (tabletData->buttons != Qt::NoButton) - xi2ReportTabletEvent(xiEvent, tabletData); + xi2ReportTabletEvent(xiEvent, tabletData); break; case XI_PropertyEvent: { // This is the wacom driver's way of reporting tool proximity. @@ -1142,9 +1151,9 @@ bool QXcbConnection::xi2HandleTabletEvent(const void *event, TabletData *tabletD // TODO maybe have a hash of tabletData->deviceId to device data so we can // look up the tablet name here, and distinguish multiple tablets if (Q_UNLIKELY(lcQpaXInputEvents().isDebugEnabled())) - qCDebug(lcQpaXInputEvents, "XI2 proximity change on tablet %d (USB %x): last tool: %x id %x current tool: %x id %x TabletDevice %d", + qCDebug(lcQpaXInputEvents, "XI2 proximity change on tablet %d (USB %x): last tool: %x id %x current tool: %x id %x %s", tabletData->deviceId, ptr[_WACSER_USB_ID], ptr[_WACSER_LAST_TOOL_SERIAL], ptr[_WACSER_LAST_TOOL_ID], - ptr[_WACSER_TOOL_SERIAL], ptr[_WACSER_TOOL_ID], tabletData->tool); + ptr[_WACSER_TOOL_SERIAL], ptr[_WACSER_TOOL_ID], toolName(tabletData->tool)); } XFree(data); } @@ -1167,6 +1176,7 @@ void QXcbConnection::xi2ReportTabletEvent(const void *event, TabletData *tabletD if (!xcbWindow) return; QWindow *window = xcbWindow->window(); + const Qt::KeyboardModifiers modifiers = keyboard()->translateModifiers(ev->mods.effective_mods); const double scale = 65536.0; QPointF local(ev->event_x / scale, ev->event_y / scale); QPointF global(ev->root_x / scale, ev->root_y / scale); @@ -1207,18 +1217,19 @@ void QXcbConnection::xi2ReportTabletEvent(const void *event, TabletData *tabletD } if (Q_UNLIKELY(lcQpaXInputEvents().isDebugEnabled())) - qCDebug(lcQpaXInputEvents, "XI2 event on tablet %d with tool %d type %d seq %d detail %d time %d " - "pos %6.1f, %6.1f root pos %6.1f, %6.1f buttons 0x%x pressure %4.2lf tilt %d, %d rotation %6.2lf", - tabletData->deviceId, tabletData->tool, ev->evtype, ev->sequenceNumber, ev->detail, ev->time, + qCDebug(lcQpaXInputEvents, "XI2 event on tablet %d with tool %s type %s seq %d detail %d time %d " + "pos %6.1f, %6.1f root pos %6.1f, %6.1f buttons 0x%x pressure %4.2lf tilt %d, %d rotation %6.2lf modifiers 0x%x", + tabletData->deviceId, toolName(tabletData->tool), pointerTypeName(tabletData->pointerType), + ev->sequenceNumber, ev->detail, ev->time, fixed1616ToReal(ev->event_x), fixed1616ToReal(ev->event_y), fixed1616ToReal(ev->root_x), fixed1616ToReal(ev->root_y), - (int)tabletData->buttons, pressure, xTilt, yTilt, rotation); + (int)tabletData->buttons, pressure, xTilt, yTilt, rotation, (int)modifiers); QWindowSystemInterface::handleTabletEvent(window, ev->time, local, global, tabletData->tool, tabletData->pointerType, tabletData->buttons, pressure, xTilt, yTilt, tangentialPressure, - rotation, 0, tabletData->serialId); + rotation, 0, tabletData->serialId, modifiers); } QXcbConnection::TabletData *QXcbConnection::tabletDataForDevice(int id) diff --git a/src/plugins/platforms/xcb/qxcbintegration.cpp b/src/plugins/platforms/xcb/qxcbintegration.cpp index af9ffab8ae..40858b39e0 100644 --- a/src/plugins/platforms/xcb/qxcbintegration.cpp +++ b/src/plugins/platforms/xcb/qxcbintegration.cpp @@ -214,6 +214,27 @@ QPlatformWindow *QXcbIntegration::createPlatformWindow(QWindow *window) const return xcbWindow; } +class QXcbForeignWindow : public QXcbWindow +{ +public: + QXcbForeignWindow(QWindow *window, WId nativeHandle) + : QXcbWindow(window) { m_window = nativeHandle; } + ~QXcbForeignWindow() {} + bool isForeignWindow() const override { return true; } + +protected: + // No-ops + void create() override {} + void destroy() override {} +}; + +QPlatformWindow *QXcbIntegration::createForeignWindow(QWindow *window, WId nativeHandle) const +{ + QXcbWindow *xcbWindow = new QXcbForeignWindow(window, nativeHandle); + xcbWindow->create(); + return xcbWindow; +} + #ifndef QT_NO_OPENGL QPlatformOpenGLContext *QXcbIntegration::createPlatformOpenGLContext(QOpenGLContext *context) const { @@ -384,9 +405,6 @@ QVariant QXcbIntegration::styleHint(QPlatformIntegration::StyleHint hint) const case QPlatformIntegration::PasswordMaskCharacter: // TODO using various xcb, gnome or KDE settings break; // Not implemented, use defaults - case QPlatformIntegration::FontSmoothingGamma: - // Match Qt 4.8 text rendering, and rendering of other X11 toolkits. - return qreal(1.0); case QPlatformIntegration::StartDragDistance: { // The default (in QPlatformTheme::defaultThemeHint) is 10 pixels, but // on a high-resolution screen it makes sense to increase it. diff --git a/src/plugins/platforms/xcb/qxcbintegration.h b/src/plugins/platforms/xcb/qxcbintegration.h index f8034f436f..baa5c9d835 100644 --- a/src/plugins/platforms/xcb/qxcbintegration.h +++ b/src/plugins/platforms/xcb/qxcbintegration.h @@ -61,6 +61,7 @@ public: ~QXcbIntegration(); QPlatformWindow *createPlatformWindow(QWindow *window) const override; + QPlatformWindow *createForeignWindow(QWindow *window, WId nativeHandle) const override; #ifndef QT_NO_OPENGL QPlatformOpenGLContext *createPlatformOpenGLContext(QOpenGLContext *context) const override; #endif diff --git a/src/plugins/platforms/xcb/qxcbkeyboard.cpp b/src/plugins/platforms/xcb/qxcbkeyboard.cpp index a5aff7f11f..2e29c208c7 100644 --- a/src/plugins/platforms/xcb/qxcbkeyboard.cpp +++ b/src/plugins/platforms/xcb/qxcbkeyboard.cpp @@ -1136,12 +1136,6 @@ int QXcbKeyboard::keysymToQtKey(xcb_keysym_t keysym, Qt::KeyboardModifiers &modi QXcbKeyboard::QXcbKeyboard(QXcbConnection *connection) : QXcbObject(connection) - , m_autorepeat_code(0) - , xkb_context(0) - , xkb_keymap(0) - , xkb_state(0) - , latin_keymap(0) - , m_hasLatinLayout(false) { memset(&xkb_names, 0, sizeof(xkb_names)); #if QT_CONFIG(xkb) diff --git a/src/plugins/platforms/xcb/qxcbkeyboard.h b/src/plugins/platforms/xcb/qxcbkeyboard.h index dfd2926435..74f9da0353 100644 --- a/src/plugins/platforms/xcb/qxcbkeyboard.h +++ b/src/plugins/platforms/xcb/qxcbkeyboard.h @@ -106,14 +106,14 @@ protected: private: void updateXKBStateFromState(struct xkb_state *kb_state, quint16 state); - bool m_config; - xcb_keycode_t m_autorepeat_code; + bool m_config = false; + xcb_keycode_t m_autorepeat_code = 0; - struct xkb_context *xkb_context; - struct xkb_keymap *xkb_keymap; - struct xkb_state *xkb_state; + struct xkb_context *xkb_context = nullptr; + struct xkb_keymap *xkb_keymap = nullptr; + struct xkb_state *xkb_state = nullptr; struct xkb_rule_names xkb_names; - mutable struct xkb_keymap *latin_keymap; + mutable struct xkb_keymap *latin_keymap = nullptr; struct _mod_masks { uint alt; @@ -143,7 +143,7 @@ private: _mod_masks vmod_masks; int core_device_id; #endif - bool m_hasLatinLayout; + bool m_hasLatinLayout = false; }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/xcb/qxcbnativeinterface.cpp b/src/plugins/platforms/xcb/qxcbnativeinterface.cpp index b1575cbee4..725288633a 100644 --- a/src/plugins/platforms/xcb/qxcbnativeinterface.cpp +++ b/src/plugins/platforms/xcb/qxcbnativeinterface.cpp @@ -90,8 +90,7 @@ static int resourceType(const QByteArray &key) } QXcbNativeInterface::QXcbNativeInterface() : - m_genericEventFilterType(QByteArrayLiteral("xcb_generic_event_t")), - m_sysTraySelectionAtom(XCB_ATOM_NONE) + m_genericEventFilterType(QByteArrayLiteral("xcb_generic_event_t")) { } diff --git a/src/plugins/platforms/xcb/qxcbnativeinterface.h b/src/plugins/platforms/xcb/qxcbnativeinterface.h index a830829311..4186d77f4d 100644 --- a/src/plugins/platforms/xcb/qxcbnativeinterface.h +++ b/src/plugins/platforms/xcb/qxcbnativeinterface.h @@ -129,7 +129,7 @@ private: const QByteArray m_genericEventFilterType; - xcb_atom_t m_sysTraySelectionAtom; + xcb_atom_t m_sysTraySelectionAtom = XCB_ATOM_NONE; static QXcbScreen *qPlatformScreenForWindow(QWindow *window); diff --git a/src/plugins/platforms/xcb/qxcbscreen.cpp b/src/plugins/platforms/xcb/qxcbscreen.cpp index 0ad9c97521..5e136b5d7e 100644 --- a/src/plugins/platforms/xcb/qxcbscreen.cpp +++ b/src/plugins/platforms/xcb/qxcbscreen.cpp @@ -59,7 +59,6 @@ QXcbVirtualDesktop::QXcbVirtualDesktop(QXcbConnection *connection, xcb_screen_t : QXcbObject(connection) , m_screen(screen) , m_number(number) - , m_xSettings(Q_NULLPTR) { const QByteArray cmAtomName = "_NET_WM_CM_S" + QByteArray::number(m_number); m_net_wm_cm_atom = connection->internAtom(cmAtomName.constData()); @@ -175,20 +174,10 @@ QXcbScreen::QXcbScreen(QXcbConnection *connection, QXcbVirtualDesktop *virtualDe , m_virtualDesktop(virtualDesktop) , m_output(outputId) , m_crtc(output ? output->crtc : XCB_NONE) - , m_mode(XCB_NONE) - , m_primary(false) - , m_rotation(XCB_RANDR_ROTATION_ROTATE_0) , m_outputName(getOutputName(output)) , m_outputSizeMillimeters(output ? QSize(output->mm_width, output->mm_height) : QSize()) , m_virtualSize(virtualDesktop->size()) , m_virtualSizeMillimeters(virtualDesktop->physicalSize()) - , m_orientation(Qt::PrimaryOrientation) - , m_refreshRate(60) - , m_forcedDpi(-1) - , m_pixelDensity(1) - , m_hintStyle(QFontEngine::HintStyle(-1)) - , m_subpixelType(QFontEngine::SubpixelAntialiasingType(-1)) - , m_antialiasingEnabled(-1) { if (connection->hasXRandr()) { xcb_randr_select_input(xcb_connection(), screen()->root, true); diff --git a/src/plugins/platforms/xcb/qxcbscreen.h b/src/plugins/platforms/xcb/qxcbscreen.h index 627397fcaf..4163be2969 100644 --- a/src/plugins/platforms/xcb/qxcbscreen.h +++ b/src/plugins/platforms/xcb/qxcbscreen.h @@ -95,12 +95,12 @@ private: QRect getWorkArea() const; xcb_screen_t *m_screen; - int m_number; + const int m_number; QList<QPlatformScreen *> m_screens; - QXcbXSettings *m_xSettings; - xcb_atom_t m_net_wm_cm_atom; - bool m_compositingActive; + QXcbXSettings *m_xSettings = nullptr; + xcb_atom_t m_net_wm_cm_atom = 0; + bool m_compositingActive = false; QRect m_workArea; }; @@ -186,9 +186,9 @@ private: QXcbVirtualDesktop *m_virtualDesktop; xcb_randr_output_t m_output; xcb_randr_crtc_t m_crtc; - xcb_randr_mode_t m_mode; - bool m_primary; - uint8_t m_rotation; + xcb_randr_mode_t m_mode = XCB_NONE; + bool m_primary = false; + uint8_t m_rotation = XCB_RANDR_ROTATION_ROTATE_0; QString m_outputName; QSizeF m_outputSizeMillimeters; @@ -197,18 +197,18 @@ private: QRect m_availableGeometry; QSize m_virtualSize; QSizeF m_virtualSizeMillimeters; - Qt::ScreenOrientation m_orientation; + Qt::ScreenOrientation m_orientation = Qt::PrimaryOrientation; QString m_windowManagerName; - bool m_syncRequestSupported; + bool m_syncRequestSupported = false; QMap<xcb_visualid_t, xcb_visualtype_t> m_visuals; QMap<xcb_visualid_t, quint8> m_visualDepths; QXcbCursor *m_cursor; - int m_refreshRate; - int m_forcedDpi; - int m_pixelDensity; - QFontEngine::HintStyle m_hintStyle; - QFontEngine::SubpixelAntialiasingType m_subpixelType; - int m_antialiasingEnabled; + int m_refreshRate = 60; + int m_forcedDpi = -1; + int m_pixelDensity = 1; + QFontEngine::HintStyle m_hintStyle = QFontEngine::HintStyle(-1); + QFontEngine::SubpixelAntialiasingType m_subpixelType = QFontEngine::SubpixelAntialiasingType(-1); + int m_antialiasingEnabled = -1; }; #ifndef QT_NO_DEBUG_STREAM diff --git a/src/plugins/platforms/xcb/qxcbsystemtraytracker.cpp b/src/plugins/platforms/xcb/qxcbsystemtraytracker.cpp index 5522af86de..fb0a4a3939 100644 --- a/src/plugins/platforms/xcb/qxcbsystemtraytracker.cpp +++ b/src/plugins/platforms/xcb/qxcbsystemtraytracker.cpp @@ -80,7 +80,6 @@ QXcbSystemTrayTracker::QXcbSystemTrayTracker(QXcbConnection *connection, , m_selection(selection) , m_trayAtom(trayAtom) , m_connection(connection) - , m_trayWindow(0) { } diff --git a/src/plugins/platforms/xcb/qxcbsystemtraytracker.h b/src/plugins/platforms/xcb/qxcbsystemtraytracker.h index a6131e6d0e..a95b9374e9 100644 --- a/src/plugins/platforms/xcb/qxcbsystemtraytracker.h +++ b/src/plugins/platforms/xcb/qxcbsystemtraytracker.h @@ -77,7 +77,7 @@ private: const xcb_atom_t m_selection; const xcb_atom_t m_trayAtom; QXcbConnection *m_connection; - xcb_window_t m_trayWindow; + xcb_window_t m_trayWindow = 0; }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/xcb/qxcbwindow.cpp b/src/plugins/platforms/xcb/qxcbwindow.cpp index 15ca68c663..f6fa903ec2 100644 --- a/src/plugins/platforms/xcb/qxcbwindow.cpp +++ b/src/plugins/platforms/xcb/qxcbwindow.cpp @@ -314,22 +314,6 @@ static const char *wm_window_role_property_id = "_q_xcb_wm_window_role"; QXcbWindow::QXcbWindow(QWindow *window) : QPlatformWindow(window) - , m_window(0) - , m_cmap(0) - , m_syncCounter(0) - , m_gravity(XCB_GRAVITY_STATIC) - , m_mapped(false) - , m_transparent(false) - , m_usingSyncProtocol(false) - , m_deferredActivation(false) - , m_embedded(false) - , m_alertState(false) - , m_netWmUserTimeWindow(XCB_NONE) - , m_dirtyFrameMargins(false) - , m_lastWindowStateEvent(-1) - , m_syncState(NoSyncNeeded) - , m_pendingSyncRequest(0) - , m_currentBitmapCursor(XCB_CURSOR_NONE) { setConnection(xcbScreen()->connection()); } @@ -357,11 +341,6 @@ enum { void QXcbWindow::create() { - if (window()->type() == Qt::ForeignWindow) { - m_window = window()->winId(); - return; - } - destroy(); m_windowState = Qt::WindowNoState; @@ -413,7 +392,7 @@ void QXcbWindow::create() xcb_window_t xcb_parent_id = platformScreen->root(); if (parent()) { xcb_parent_id = static_cast<QXcbWindow *>(parent())->xcb_window(); - m_embedded = parent()->window()->type() == Qt::ForeignWindow; + m_embedded = parent()->isForeignWindow(); QSurfaceFormat parentFormat = parent()->window()->requestedFormat(); if (window()->surfaceType() != QSurface::OpenGLSurface && parentFormat.hasAlpha()) { @@ -606,9 +585,10 @@ QXcbWindow::~QXcbWindow() if (m_currentBitmapCursor != XCB_CURSOR_NONE) { xcb_free_cursor(xcb_connection(), m_currentBitmapCursor); } - if (window()->type() != Qt::ForeignWindow) - destroy(); - else { + + destroy(); + + if (isForeignWindow()) { if (connection()->mouseGrabber() == this) connection()->setMouseGrabber(Q_NULLPTR); if (connection()->mousePressWindow() == this) @@ -1522,7 +1502,7 @@ void QXcbWindow::setParent(const QPlatformWindow *parent) if (parent) { const QXcbWindow *qXcbParent = static_cast<const QXcbWindow *>(parent); xcb_parent_id = qXcbParent->xcb_window(); - m_embedded = qXcbParent->window()->type() == Qt::ForeignWindow; + m_embedded = qXcbParent->isForeignWindow(); } else { xcb_parent_id = xcbScreen()->root(); m_embedded = false; @@ -2155,12 +2135,9 @@ bool QXcbWindow::isExposed() const return m_mapped; } -bool QXcbWindow::isEmbedded(const QPlatformWindow *parentWindow) const +bool QXcbWindow::isEmbedded() const { - if (!m_embedded) - return false; - - return parentWindow ? (parentWindow == parent()) : true; + return m_embedded; } QPoint QXcbWindow::mapToGlobal(const QPoint &pos) const diff --git a/src/plugins/platforms/xcb/qxcbwindow.h b/src/plugins/platforms/xcb/qxcbwindow.h index d100120d46..b4d947e700 100644 --- a/src/plugins/platforms/xcb/qxcbwindow.h +++ b/src/plugins/platforms/xcb/qxcbwindow.h @@ -87,7 +87,7 @@ public: void setParent(const QPlatformWindow *window) override; bool isExposed() const override; - bool isEmbedded(const QPlatformWindow *parentWindow = 0) const override; + bool isEmbedded() const override; QPoint mapToGlobal(const QPoint &pos) const override; QPoint mapFromGlobal(const QPoint &pos) const override; @@ -233,48 +233,48 @@ protected: void handleLeaveNotifyEvent(int root_x, int root_y, quint8 mode, quint8 detail, xcb_timestamp_t timestamp); - xcb_window_t m_window; - xcb_colormap_t m_cmap; + xcb_window_t m_window = 0; + xcb_colormap_t m_cmap = 0; - uint m_depth; - QImage::Format m_imageFormat; - bool m_imageRgbSwap; + uint m_depth = 0; + QImage::Format m_imageFormat = QImage::Format_ARGB32_Premultiplied; + bool m_imageRgbSwap = false; xcb_sync_int64_t m_syncValue; - xcb_sync_counter_t m_syncCounter; + xcb_sync_counter_t m_syncCounter = 0; - Qt::WindowState m_windowState; + Qt::WindowState m_windowState = Qt::WindowNoState; - xcb_gravity_t m_gravity; + xcb_gravity_t m_gravity = XCB_GRAVITY_STATIC; - bool m_mapped; - bool m_transparent; - bool m_usingSyncProtocol; - bool m_deferredActivation; - bool m_embedded; - bool m_alertState; - xcb_window_t m_netWmUserTimeWindow; + bool m_mapped = false; + bool m_transparent = false; + bool m_usingSyncProtocol = false; + bool m_deferredActivation = false; + bool m_embedded = false; + bool m_alertState = false; + xcb_window_t m_netWmUserTimeWindow = XCB_NONE; QSurfaceFormat m_format; - mutable bool m_dirtyFrameMargins; + mutable bool m_dirtyFrameMargins = false; mutable QMargins m_frameMargins; QRegion m_exposeRegion; QSize m_oldWindowSize; - xcb_visualid_t m_visualId; - int m_lastWindowStateEvent; + xcb_visualid_t m_visualId = 0; + int m_lastWindowStateEvent = -1; enum SyncState { NoSyncNeeded, SyncReceived, SyncAndConfigureReceived }; - SyncState m_syncState; + SyncState m_syncState = NoSyncNeeded; - QXcbSyncWindowRequest *m_pendingSyncRequest; - xcb_cursor_t m_currentBitmapCursor; + QXcbSyncWindowRequest *m_pendingSyncRequest = nullptr; + xcb_cursor_t m_currentBitmapCursor = XCB_CURSOR_NONE; }; QT_END_NAMESPACE |